<?php

declare(strict_types=1);

namespace App\Controllers;

use App\Middleware\AuthMiddleware;
use App\Models\ContractCreateResult;
use App\Models\ContractDeleteResult;
use App\Models\ContractGetResult;
use App\Models\ContractSendResult;
use App\Models\ContractUpdateResult;
use App\Services\AuthService;
use App\Services\ContractService;
use ApiException;

/**
 * Contract Module — create, view, edit & send partner contracts via Karvi API.
 */
final class ContractController
{
    private ContractService $contracts;
    private AuthMiddleware $auth;

    public function __construct(?ContractService $contracts = null, ?AuthService $auth = null)
    {
        $this->contracts = $contracts ?? contract_service();
        $this->auth = new AuthMiddleware($auth ?? auth_service());
    }

    public function showCreateForm(): void
    {
        $this->auth->requireAuth();

        require_once dirname(__DIR__) . '/includes/api_service.php';
        require_once dirname(__DIR__) . '/includes/contract_form.php';

        $layoutGroups = contract_form_create_layout_groups();
        $usingPartnerApi = function_exists('api_can_use_partner_api') && api_can_use_partner_api();
        $usingLocalStore = function_exists('api_show_local_store_notice') && api_show_local_store_notice();
        $action = function_exists('app_path') ? app_path('/admin/create') : '/admin/create';
        $error = '';

        require dirname(__DIR__) . '/views/contracts/create.php';
    }

    public function store(): void
    {
        $this->auth->requireAuth();

        require_once dirname(__DIR__) . '/includes/api_service.php';
        require_once dirname(__DIR__) . '/includes/contract_form.php';
        require_once dirname(__DIR__) . '/includes/api_client.php';

        $token = generate_token();
        $contractData = collect_contract_from_post($_POST, $token);
        $contractData['type'] = api_normalize_contract_type((string)($_POST['type'] ?? $contractData['type'] ?? 'partner'));

        try {
            $contractData['raw_data_override'] = $this->contracts->buildPayloadFromPost($_POST)['raw_data'] ?? [];
        } catch (ApiException $e) {
            set_flash($e->getMessage(), 'error');
            redirect('/admin/create');
        }

        $validationError = validate_contract_form($contractData);
        if ($validationError) {
            set_flash($validationError, 'error', true);
            redirect('/admin/create');
        }

        $environmentError = admin_create_environment_check();
        if ($environmentError) {
            set_flash($environmentError, 'error');
            redirect('/admin/create');
        }

        if (!function_exists('api_can_use_partner_api') || !api_can_use_partner_api()) {
            set_flash('Not authenticated with Karvi Partner API. Please log in again.', 'error');
            redirect('/admin/login/');
        }

        $result = $this->contracts->createContractFromRecord($contractData);
        $this->handleCreateResult($result);
    }

    private function handleCreateResult(ContractCreateResult $result): void
    {
        if (!$result->success) {
            set_flash($result->message, 'error');
            redirect('/admin/create');
        }

        auth_start();
        $_SESSION['last_contract_create_response'] = [
            'message' => $result->message !== '' ? $result->message : 'Contract created.',
            'id' => $result->id(),
            'restaurant_name' => $result->restaurantName(),
            'owner_name' => $result->ownerName(),
            'email' => $result->email(),
            'contract_status' => $result->contractStatus(),
            'sign_url' => $result->signUrl(),
            'sign_token' => $result->signToken(),
            'created_at' => $result->createdAt(),
            'updated_at' => $result->updatedAt(),
            'api_response' => $result->apiResponse,
        ];

        set_flash($result->message !== '' ? $result->message : 'Contract created.', 'success', true);

        $contractId = $result->id();
        if ($contractId !== null && $contractId > 0) {
            redirect('/admin/contracts/' . $contractId);
        }

        $savedToken = trim((string)($result->contract['token'] ?? $result->signToken()));
        redirect('/admin/create/link?token=' . rawurlencode($savedToken));
    }

    public function show(int $contractId): void
    {
        $this->auth->requireAuth();

        require_once dirname(__DIR__) . '/includes/api_service.php';
        require_once dirname(__DIR__) . '/includes/contract_details.php';

        $backUrl = function_exists('app_path') ? app_path('/admin/dashboard') : '/admin/dashboard';

        if (!function_exists('api_can_use_partner_api') || !api_can_use_partner_api()) {
            set_flash('Not authenticated with Karvi Partner API. Please log in again.', 'error');
            redirect('/admin/login/');
        }

        $result = $this->contracts->getContract($contractId);
        $contract = is_array($result->contract) ? $result->contract : [];
        $rawData = $result->rawData();
        $errorCode = $result->errorCode;
        $httpStatus = $result->httpStatus;
        $editUrl = $result->success && function_exists('app_path')
            ? app_path('/admin/contracts/' . $contractId . '/edit')
            : ($result->success ? '/admin/contracts/' . $contractId . '/edit' : '');
        $sendUrl = $result->success && function_exists('app_path')
            ? app_path('/admin/contracts/' . $contractId . '/send')
            : ($result->success ? '/admin/contracts/' . $contractId . '/send' : '');
        $deleteUrl = $result->success && function_exists('app_path')
            ? app_path('/admin/contracts/' . $contractId . '/delete')
            : ($result->success ? '/admin/contracts/' . $contractId . '/delete' : '');
        $signToken = trim((string)($contract['sign_token'] ?? $contract['token'] ?? ''));

        auth_start();
        $sendResult = $_SESSION['last_contract_send_response'] ?? null;
        unset($_SESSION['last_contract_send_response']);
        $createResult = $_SESSION['last_contract_create_response'] ?? null;
        unset($_SESSION['last_contract_create_response']);

        $signingUrl = is_array($sendResult)
            ? trim((string)($sendResult['sign_url'] ?? ''))
            : trim((string)($contract['sign_url'] ?? ''));
        $signingToken = is_array($sendResult)
            ? trim((string)($sendResult['sign_token'] ?? ''))
            : trim((string)($contract['sign_token'] ?? $signToken));
        if ($signingToken !== '') {
            $signingUrl = contract_public_sign_url($signingToken);
        }

        require dirname(__DIR__) . '/views/contracts/show.php';
    }

    public function showEditForm(int $contractId): void
    {
        $this->auth->requireAuth();

        require_once dirname(__DIR__) . '/includes/api_service.php';
        require_once dirname(__DIR__) . '/includes/contract_details.php';

        if (!function_exists('api_can_use_partner_api') || !api_can_use_partner_api()) {
            set_flash('Not authenticated with Karvi Partner API. Please log in again.', 'error');
            redirect('/admin/login/');
        }

        $result = $this->contracts->getContract($contractId);
        if (!$result->success) {
            set_flash($result->message, 'error');
            redirect('/admin/contracts/' . $contractId);
        }

        $contract = is_array($result->contract) ? $result->contract : [];
        $rawData = $result->rawData();
        $action = function_exists('app_path') ? app_path('/admin/contracts/' . $contractId . '/edit') : '/admin/contracts/' . $contractId . '/edit';
        $detailsUrl = function_exists('app_path') ? app_path('/admin/contracts/' . $contractId) : '/admin/contracts/' . $contractId;
        $backUrl = function_exists('app_path') ? app_path('/admin/dashboard') : '/admin/dashboard';

        require dirname(__DIR__) . '/views/contracts/edit.php';
    }

    public function update(int $contractId): void
    {
        $this->auth->requireAuth();

        require_once dirname(__DIR__) . '/includes/api_service.php';

        if (!function_exists('api_can_use_partner_api') || !api_can_use_partner_api()) {
            set_flash('Not authenticated with Karvi Partner API. Please log in again.', 'error');
            redirect('/admin/login/');
        }

        if ($contractId <= 0) {
            set_flash('Invalid contract ID.', 'error');
            redirect('/admin/dashboard');
        }

        $result = $this->contracts->updateContractFromPost($contractId, $_POST);
        $this->handleUpdateResult($result, $contractId);
    }

    private function handleUpdateResult(ContractUpdateResult $result, int $contractId): void
    {
        if (!$result->success) {
            set_flash($result->message, 'error');
            redirect('/admin/contracts/' . $contractId . '/edit');
        }

        auth_start();
        $_SESSION['last_contract_update_response'] = [
            'message' => $result->message,
            'updated_at' => $result->updatedAt(),
            'api_response' => $result->apiResponse,
            'contract' => $result->refreshedContract ?? $result->contract,
        ];

        set_flash($result->message !== '' ? $result->message : 'Contract updated.', 'success', true);
        redirect('/admin/contracts/' . $contractId);
    }

    public function send(int $contractId): void
    {
        $this->auth->requireAuth();

        require_once dirname(__DIR__) . '/includes/api_service.php';

        if (!function_exists('api_can_use_partner_api') || !api_can_use_partner_api()) {
            set_flash('Not authenticated with Karvi Partner API. Please log in again.', 'error');
            redirect('/admin/login/');
        }

        if ($contractId <= 0) {
            set_flash('Invalid contract ID.', 'error');
            redirect('/admin/dashboard');
        }

        $result = $this->contracts->sendContract($contractId);
        $this->handleSendResult($result, $contractId);
    }

    private function handleSendResult(ContractSendResult $result, int $contractId): void
    {
        if (!$result->success) {
            set_flash($result->message, 'error');
            redirect('/admin/contracts/' . $contractId);
        }

        auth_start();
        $_SESSION['last_contract_send_response'] = [
            'message' => $result->message !== '' ? $result->message : 'Contract sent successfully.',
            'sign_url' => $result->signUrl,
            'sign_token' => $result->signToken,
            'api_response' => $result->apiResponse,
        ];

        set_flash($result->message !== '' ? $result->message : 'Contract sent successfully.', 'success', true);
        redirect('/admin/contracts/' . $contractId);
    }

    public function destroy(int $contractId): void
    {
        $this->auth->requireAuth();

        require_once dirname(__DIR__) . '/includes/api_service.php';

        if (!function_exists('api_can_use_partner_api') || !api_can_use_partner_api()) {
            set_flash('Not authenticated with Karvi Partner API. Please log in again.', 'error');
            redirect('/admin/login/');
        }

        if ($contractId <= 0) {
            set_flash('Invalid contract ID.', 'error');
            redirect('/admin/dashboard');
        }

        $token = trim((string)($_POST['token'] ?? ''));
        $detailsUrl = function_exists('app_path')
            ? app_path('/admin/contracts/' . $contractId)
            : '/admin/contracts/' . $contractId;

        try {
            $result = $this->contracts->deleteContract($contractId);
            if (!$result->success) {
                set_flash($result->message, 'error');
                redirect($detailsUrl);
            }

            if ($token !== '') {
                require_once dirname(__DIR__) . '/includes/local_store.php';
                require_once dirname(__DIR__) . '/includes/contract_admin.php';

                $contract = local_store_find($token);
                $signatures = api_get_signatures_for_token($token);

                if ($contract !== null) {
                    local_store_delete_contract($token);
                } else {
                    $contract = api_find_contract($token);
                    if ($contract !== null) {
                        contract_delete_related_files($token, $contract, $signatures);
                    }
                }
            }

            $this->handleDeleteResult($result, $contractId);
        } catch (\Throwable $e) {
            set_flash(api_error_message($e), 'error');
            redirect($detailsUrl);
        }
    }

    private function handleDeleteResult(ContractDeleteResult $result, int $contractId): void
    {
        auth_start();
        $_SESSION['last_contract_delete_response'] = [
            'message' => $result->message,
            'deleted_id' => $result->deletedId ?? $contractId,
            'api_response' => $result->apiResponse,
        ];

        set_flash($result->message !== '' ? $result->message : 'Contract deleted.', 'success', true);
        redirect('/admin/dashboard');
    }
}
