<?php
declare(strict_types=1);

namespace App\Modules\Carnets\Controllers;

use App\Core\Controller;
use App\Core\Request;
use App\Core\Response;
use App\Core\App;
use App\Core\EventBus;
use App\Modules\Carnets\Models\Carnet;
use App\Modules\Carnets\Services\CarnetPrintService;
use App\Modules\Carnets\Services\QRCodeGenerator;
use App\Modules\Pricing\Services\PricingEngine;
use App\Modules\Rules\Services\RuleEngine;
use App\Modules\Cashier\Services\PaymentRequestService;

class CarnetController extends Controller
{
    public function index(Request $request): Response
    {
        $filters = [
            'search'    => trim((string) $request->get('q', '')),
            'is_active' => $request->get('is_active', ''),
            'type'      => $request->get('type', ''),
        ];
        $page = max(1, (int) $request->get('page', 1));
        $result = Carnet::search($filters, 25, $page);

        return $this->view('Carnets.Views.index', [
            'rows'       => $result['data'],
            'pagination' => $result['pagination'],
            'filters'    => $filters,
        ]);
    }

    public function issue(Request $request, string $memberId): Response
    {
        $db = App::getInstance()->db();
        $member = $db->selectOne("SELECT * FROM members WHERE id = ? AND is_archived = 0", [(int) $memberId]);
        if (!$member) {
            return $this->redirect('/members')->withError('العضو غير موجود');
        }

        // Check eligibility
        $blockReasons = CarnetPrintService::checkEligibility((int) $memberId);
        if (!empty($blockReasons)) {
            $session = App::getInstance()->session();
            $session->flash('_alerts', array_map(fn($r) => ['type' => 'error', 'message' => $r], $blockReasons));
            return $this->redirect("/members/{$memberId}");
        }

        $employee = App::getInstance()->currentEmployee();

        // Deactivate any existing active carnet
        $existingActive = Carnet::getActiveForMember((int) $memberId);
        if ($existingActive) {
            $db->update('carnets', [
                'is_active'          => 0,
                'deactivated_at'     => date('Y-m-d H:i:s'),
                'deactivated_reason' => 'إصدار كارنيه جديد',
                'updated_at'         => date('Y-m-d H:i:s'),
            ], '`id` = ?', [(int) $existingActive['id']]);
        }

        // Generate carnet number
        $carnetNumber = Carnet::generateNumber();

        // Generate QR code data
        $qrData = QRCodeGenerator::encode($member['membership_number'] ?? (string) $member['id']);

        // Determine carnet type
        $carnetType = 'regular';
        if ($member['membership_type'] === 'seasonal') {
            $carnetType = 'seasonal';
        }

        $carnet = Carnet::create([
            'member_id'          => (int) $memberId,
            'carnet_number'      => $carnetNumber,
            'carnet_type'        => $carnetType,
            'qr_code_data'       => $qrData,
            'is_active'          => 1,
            'issued_by'          => $employee ? (int) $employee->id : null,
            'replacement_count'  => $existingActive ? (int) ($existingActive['replacement_count'] ?? 0) + 1 : 0,
            'previous_carnet_id' => $existingActive ? (int) $existingActive['id'] : null,
        ]);

        EventBus::dispatch('carnet.issued', [
            'carnet_id'    => (int) $carnet->id,
            'member_id'    => (int) $memberId,
            'carnet_number'=> $carnetNumber,
            'issued_by'    => $employee ? (int) $employee->id : null,
        ]);

        return $this->redirect("/carnets/{$carnet->id}/print")->withSuccess('تم إصدار الكارنيه رقم: ' . $carnetNumber);
    }

    public function print(Request $request, string $id): Response
    {
        $db = App::getInstance()->db();
        $carnet = $db->selectOne(
            "SELECT c.*, m.full_name_ar, m.full_name_en, m.membership_number, m.membership_type,
                    m.photo_path, m.branch_id, b.name_ar as branch_name, b.name_en as branch_name_en
             FROM carnets c
             JOIN members m ON m.id = c.member_id
             LEFT JOIN branches b ON b.id = m.branch_id
             WHERE c.id = ?",
            [(int) $id]
        );
        if (!$carnet) {
            return $this->redirect('/carnets')->withError('الكارنيه غير موجود');
        }

        // Record print
        $employee = App::getInstance()->currentEmployee();
        $db->update('carnets', [
            'print_count'     => (int) $carnet['print_count'] + 1,
            'last_printed_at' => date('Y-m-d H:i:s'),
            'last_printed_by' => $employee ? (int) $employee->id : null,
            'updated_at'      => date('Y-m-d H:i:s'),
        ], '`id` = ?', [(int) $id]);

        EventBus::dispatch('carnet.printed', [
            'carnet_id'  => (int) $id,
            'member_id'  => (int) $carnet['member_id'],
            'printed_by' => $employee ? (int) $employee->id : null,
            'print_count'=> (int) $carnet['print_count'] + 1,
        ]);

        $qrSvg = QRCodeGenerator::renderSvg($carnet['qr_code_data'] ?? ($carnet['membership_number'] ?? ''));

        return $this->view('Carnets.Views.print', [
            'carnet' => $carnet,
            'qrSvg'  => $qrSvg,
        ]);
    }

    public function issueDependent(Request $request, string $memberId, string $type, string $dependentId): Response
    {
        $db = App::getInstance()->db();
        $member = $db->selectOne("SELECT * FROM members WHERE id = ? AND is_archived = 0", [(int) $memberId]);
        if (!$member) {
            return $this->redirect('/members')->withError('العضو غير موجود');
        }

        $allowedTypes = ['spouses', 'children', 'temporary_members'];
        if (!in_array($type, $allowedTypes, true)) {
            return $this->redirect("/members/{$memberId}")->withError('نوع التابع غير صالح');
        }

        $dependent = $db->selectOne("SELECT * FROM {$type} WHERE id = ? AND member_id = ? AND is_archived = 0", [(int) $dependentId, (int) $memberId]);
        if (!$dependent) {
            return $this->redirect("/members/{$memberId}")->withError('التابع غير موجود');
        }

        $blockReasons = CarnetPrintService::checkDependentEligibility((int) $memberId, $type, (int) $dependentId);
        if (!empty($blockReasons)) {
            $session = App::getInstance()->session();
            $session->flash('_alerts', array_map(fn($r) => ['type' => 'error', 'message' => $r], $blockReasons));
            return $this->redirect("/members/{$memberId}");
        }

        $employee = App::getInstance()->currentEmployee();

        $existingActive = Carnet::getActiveForDependent($type, (int) $dependentId);
        if ($existingActive) {
            $db->update('carnets', [
                'is_active'          => 0,
                'deactivated_at'     => date('Y-m-d H:i:s'),
                'deactivated_reason' => 'إصدار كارنيه جديد',
                'updated_at'         => date('Y-m-d H:i:s'),
            ], '`id` = ?', [(int) $existingActive['id']]);
        }

        $carnetNumber = Carnet::generateNumber();
        $qrData = QRCodeGenerator::encode(($member['membership_number'] ?? (string) $member['id']) . '-' . substr($type, 0, 1) . $dependentId);

        $carnet = Carnet::create([
            'member_id'          => (int) $memberId,
            'dependent_type'     => $type,
            'dependent_id'       => (int) $dependentId,
            'card_variant'       => 'dependent',
            'carnet_number'      => $carnetNumber,
            'carnet_type'        => 'regular',
            'qr_code_data'       => $qrData,
            'is_active'          => 1,
            'issued_by'          => $employee ? (int) $employee->id : null,
            'replacement_count'  => $existingActive ? (int) ($existingActive['replacement_count'] ?? 0) + 1 : 0,
            'previous_carnet_id' => $existingActive ? (int) $existingActive['id'] : null,
        ]);

        EventBus::dispatch('carnet.issued', [
            'carnet_id'      => (int) $carnet->id,
            'member_id'      => (int) $memberId,
            'dependent_type' => $type,
            'dependent_id'   => (int) $dependentId,
            'carnet_number'  => $carnetNumber,
        ]);

        return $this->redirect("/carnets/{$carnet->id}/print-dependent")->withSuccess('تم إصدار كارنيه التابع رقم: ' . $carnetNumber);
    }

    public function printDependent(Request $request, string $id): Response
    {
        $db = App::getInstance()->db();
        $carnet = $db->selectOne("SELECT * FROM carnets WHERE id = ? AND dependent_type IS NOT NULL", [(int) $id]);
        if (!$carnet) {
            return $this->redirect('/carnets')->withError('كارنيه التابع غير موجود');
        }

        $member = $db->selectOne(
            "SELECT m.full_name_ar, m.full_name_en, m.membership_number, m.photo_path, b.name_ar as branch_name
             FROM members m LEFT JOIN branches b ON b.id = m.branch_id WHERE m.id = ?",
            [(int) $carnet['member_id']]
        );

        $dependent = $db->selectOne(
            "SELECT * FROM {$carnet['dependent_type']} WHERE id = ?",
            [(int) $carnet['dependent_id']]
        );

        if (!$member || !$dependent) {
            return $this->redirect('/carnets')->withError('بيانات غير مكتملة');
        }

        $employee = App::getInstance()->currentEmployee();
        $db->update('carnets', [
            'print_count'     => (int) $carnet['print_count'] + 1,
            'last_printed_at' => date('Y-m-d H:i:s'),
            'last_printed_by' => $employee ? (int) $employee->id : null,
            'updated_at'      => date('Y-m-d H:i:s'),
        ], '`id` = ?', [(int) $id]);

        $typeLabels = [
            'spouses'           => 'زوج/زوجة',
            'children'          => 'ابن/ابنة',
            'temporary_members' => 'عضو مؤقت',
        ];

        $qrSvg = QRCodeGenerator::renderSvg($carnet['qr_code_data'] ?? '');

        return $this->view('Carnets.Views.print-dependent', [
            'carnet'        => $carnet,
            'member'        => $member,
            'dependent'     => $dependent,
            'typeLabel'     => $typeLabels[$carnet['dependent_type']] ?? 'تابع',
            'qrSvg'         => $qrSvg,
        ]);
    }

    public function replace(Request $request, string $memberId): Response
    {
        $db = App::getInstance()->db();
        $member = $db->selectOne("SELECT * FROM members WHERE id = ? AND is_archived = 0", [(int) $memberId]);
        if (!$member) {
            return $this->redirect('/members')->withError('العضو غير موجود');
        }

        $svc = PricingEngine::getServiceFee('SVC_CARNET_REPLACEMENT');
        $fee = $svc ? ($svc['base_amount'] ?? '200.00') : (RuleEngine::getValue('CARNET_REPLACEMENT_FEE', 'amount') ?? '200.00');

        PaymentRequestService::createRequest(
            (int) $memberId,
            'carnet_replacement',
            $fee,
            'رسوم بدل فاقد كارنيه',
            'carnets',
            null
        );

        return $this->redirect('/members/' . $memberId)->withSuccess('تم إرسال طلب دفع بدل فاقد الكارنيه (' . money($fee) . ') للخزينة');
    }

    public function deactivate(Request $request, string $id): Response
    {
        $db = App::getInstance()->db();
        $carnet = $db->selectOne("SELECT * FROM carnets WHERE id = ? AND is_active = 1", [(int) $id]);
        if (!$carnet) {
            return $this->redirect('/carnets')->withError('الكارنيه غير موجود أو معطل بالفعل');
        }

        $reason = trim((string) $request->post('reason', ''));
        if ($reason === '') {
            return $this->redirect('/carnets')->withError('سبب الإلغاء مطلوب');
        }

        $db->update('carnets', [
            'is_active'          => 0,
            'deactivated_at'     => date('Y-m-d H:i:s'),
            'deactivated_reason' => $reason,
            'updated_at'         => date('Y-m-d H:i:s'),
        ], '`id` = ?', [(int) $id]);

        EventBus::dispatch('carnet.deactivated', [
            'carnet_id' => (int) $id,
            'member_id' => (int) $carnet['member_id'],
            'reason'    => $reason,
        ]);

        return $this->redirect('/carnets')->withSuccess('تم إلغاء الكارنيه');
    }
}