<?php
namespace App\Controllers;

use App\Repositories\ChequeReviewRepository;
use App\Repositories\DealRepository;
use App\Services\AuthService;
use App\Database\Connection;
use App\Utils\Sanitizer;
use App\Utils\Logger;
use App\Utils\DateNormalizer;

/**
 * C9: financial cheque workflow — list cheques, approve/reject, set collection status.
 */
class ChequeController extends ApiController
{
    private $chequeRepo;
    private $dealRepo;
    private $authService;
    private $db;

    private function normalizeOptionalDateFilter(string $value, string $fieldName): string
    {
        $value = trim($value);
        if ($value === '') {
            return '';
        }
        $date = DateNormalizer::normalizeGregorianOrJalaliDate($value);
        if ($date === null) {
            $this->errorResponse($fieldName . ' نامعتبر است', 422);
        }
        return $date;
    }

    public function __construct(ChequeReviewRepository $chequeRepo, DealRepository $dealRepo, AuthService $authService, Connection $db)
    {
        $this->chequeRepo = $chequeRepo;
        $this->dealRepo = $dealRepo;
        $this->authService = $authService;
        $this->db = $db;
    }

    private function canRbac(string $cap): bool
    {
        global $app;
        if (isset($app->services->rbac) && $app->services->rbac) {
            return (bool)$app->services->rbac->can($cap);
        }
        return false;
    }

    private function requireCap(string $cap, string $msg): void
    {
        if (!$this->canRbac($cap)) {
            $this->errorResponse($msg, 403);
        }
    }

    private function currentUserDidarId(): string
    {
        return (string)($_SESSION['didar_id'] ?? $_SESSION['user_id'] ?? '');
    }

    public function list(): void
    {
        $this->requireCap('cheques.view', 'دسترسی محدود - شما مجاز به مشاهده چک‌ها نیستید');
        $requestedOwnerDidarId = Sanitizer::sanitize($_POST['owner_didar_id'] ?? $_GET['owner_didar_id'] ?? '');
        $filters = [
            'check_status' => Sanitizer::sanitize($_POST['check_status'] ?? $_GET['check_status'] ?? ''),
            'collection_status' => Sanitizer::sanitize($_POST['collection_status'] ?? $_GET['collection_status'] ?? ''),
            'search' => Sanitizer::sanitize($_POST['search'] ?? $_GET['search'] ?? ''),
            'date_from' => $this->normalizeOptionalDateFilter(Sanitizer::sanitize($_POST['date_from'] ?? $_GET['date_from'] ?? ''), 'تاریخ شروع'),
            'date_to' => $this->normalizeOptionalDateFilter(Sanitizer::sanitize($_POST['date_to'] ?? $_GET['date_to'] ?? ''), 'تاریخ پایان'),
            'limit' => (int)($_POST['limit'] ?? $_GET['limit'] ?? 50),
            'offset' => (int)($_POST['offset'] ?? $_GET['offset'] ?? 0),
        ];
        global $app;
        if (isset($app->services->rbac) && $app->services->rbac) {
            $filters = $app->services->rbac->applyOwnerScope($filters, 'cheques', $requestedOwnerDidarId);
        }
        $filters['limit'] = max(1, min(200, (int)$filters['limit']));
        $filters['offset'] = max(0, (int)$filters['offset']);
        $rows = $this->chequeRepo->listCheques($filters);
        $total = $this->chequeRepo->countCheques($filters);
        $this->successResponse([
            'cheques' => $rows,
            'count' => count($rows),
            'total' => $total,
            'limit' => $filters['limit'],
            'offset' => $filters['offset'],
            'page' => (int)floor($filters['offset'] / $filters['limit']) + 1,
        ]);
    }

    /**
     * Resolve the target cheque from the stable transaction id. Returns the
     * transaction row (id, deal_id, check_number, amount). The cheque workflow
     * is keyed on transactions.id because synced cheques usually have no
     * check_number, so (deal_id, check_number) cannot address a single cheque.
     */
    private function resolveCheque(): array
    {
        $transactionId = (int)($_POST['transaction_id'] ?? 0);
        if ($transactionId <= 0) {
            $this->errorResponse('شناسه تراکنش چک نامعتبر است');
        }
        $txn = $this->chequeRepo->getChequeTransaction($transactionId);
        if (!$txn) {
            $this->errorResponse('چک یافت نشد');
        }
        return $txn;
    }

    public function setStatus(): void
    {
        $this->requireCap('cheques.review', 'دسترسی محدود - شما مجاز به تعیین وضعیت چک نیستید');
        $txn = $this->resolveCheque();
        $transactionId = (int)$txn['id'];
        $dealId = (int)$txn['deal_id'];
        $checkNumber = trim((string)($txn['check_number'] ?? ''));
        $amount = (float)($txn['amount'] ?? 0);
        $status = strtolower(trim((string)($_POST['status'] ?? '')));
        $note = trim((string)Sanitizer::sanitize($_POST['note'] ?? ''));

        if (!in_array($status, ['pending', 'approved', 'rejected'], true)) {
            $this->errorResponse('وضعیت چک نامعتبر است');
        }
        if ($status === 'rejected' && $note === '') {
            $this->errorResponse('برای رد چک، درج توضیحات الزامی است');
        }

        $this->chequeRepo->upsertStatus($transactionId, $dealId, $checkNumber, $status, $note, $this->currentUserDidarId(), $amount);
        Logger::logInfo('CHEQUE_STATUS_SET', ['transaction_id' => $transactionId, 'deal_id' => $dealId, 'status' => $status]);
        $this->successResponse(['review' => $this->chequeRepo->getReview($transactionId)], 'وضعیت چک ثبت شد');
    }

    public function setCollection(): void
    {
        $this->requireCap('cheques.collect', 'دسترسی محدود - شما مجاز به تعیین وضعیت وصول نیستید');
        $txn = $this->resolveCheque();
        $transactionId = (int)$txn['id'];
        $dealId = (int)$txn['deal_id'];
        $checkNumber = trim((string)($txn['check_number'] ?? ''));
        $amount = (float)($txn['amount'] ?? 0);
        $status = strtolower(trim((string)($_POST['status'] ?? '')));
        $date = trim((string)Sanitizer::sanitize($_POST['collection_date'] ?? ''));

        if (!in_array($status, ['pending', 'collected', 'returned', 'blataklif'], true)) {
            $this->errorResponse('وضعیت وصول نامعتبر است');
        }
        // Expect Gregorian YYYY-MM-DD (frontend converts the Jalali picker value).
        if ($date !== '' && !preg_match('/^\d{4}-\d{2}-\d{2}$/', $date)) {
            $date = '';
        }
        if (in_array($status, ['collected', 'returned'], true) && $date === '') {
            $this->errorResponse('برای وضعیت وصول/برگشت، درج تاریخ الزامی است');
        }

        $this->chequeRepo->upsertCollection($transactionId, $dealId, $checkNumber, $status, $date, $this->currentUserDidarId(), $amount);
        Logger::logInfo('CHEQUE_COLLECTION_SET', ['transaction_id' => $transactionId, 'deal_id' => $dealId, 'status' => $status]);
        $this->successResponse(['review' => $this->chequeRepo->getReview($transactionId)], 'وضعیت وصول ثبت شد');
    }
}
