<?php
declare(strict_types=1);

namespace App\Modules\Death\Controllers;

use App\Core\Controller;
use App\Core\Request;
use App\Core\Response;
use App\Core\App;
use App\Core\EventBus;
use App\Modules\Death\Models\DeathCase;
use App\Modules\Archive\Services\ArchiveService;
use App\Modules\Rules\Services\RuleEngine;
use App\Modules\Payments\Services\PaymentService;
use App\Modules\Cashier\Services\PaymentRequestService;
use App\Modules\ServiceCatalog\Models\ServicePrice;
use App\Modules\Members\Models\Member;

class DeathController extends Controller
{
    private static function getFees(): array
    {
        $formFee = ServicePrice::getPrice('SVC_TRANSFER_FORM', '570.00');
        $annualSubBase = ServicePrice::getPrice('SVC_ANNUAL_MEMBER', '492.00');
        $devFeeData = RuleEngine::get('DEVELOPMENT_FEE');
        $devFee = $devFeeData['amount'] ?? '35.00';
        $annualSub = bcadd($annualSubBase, $devFee, 2);
        $totalFee = bcadd($formFee, $annualSub, 2);
        return compact('formFee', 'annualSubBase', 'devFee', 'annualSub', 'totalFee');
    }

    public function index(Request $request): Response
    {
        $filters = ['search' => trim((string) $request->get('q', '')), 'status' => $request->get('status', '')];
        $page = max(1, (int) $request->get('page', 1));
        $result = DeathCase::search($filters, 25, $page);
        return $this->view('Death.Views.index', ['rows' => $result['data'], 'pagination' => $result['pagination'], 'filters' => $filters]);
    }

    public function create(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('العضو غير موجود');
        $spouses = $db->select("SELECT * FROM spouses WHERE member_id = ? AND is_archived = 0 AND status = 'active' ORDER BY spouse_order", [(int) $memberId]);
        $children = $db->select("SELECT * FROM children WHERE member_id = ? AND is_archived = 0 ORDER BY child_order", [(int) $memberId]);
        $fees = self::getFees();

        return $this->view('Death.Views.create', [
            'member'     => $member,
            'spouses'    => $spouses,
            'children'   => $children,
            'form_fee'   => $fees['formFee'],
            'annual_sub' => $fees['annualSub'],
            'total_fee'  => $fees['totalFee'],
        ]);
    }

    public function store(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('العضو غير موجود');

        $deceasedType = trim($request->post('deceased_type', ''));
        $deathDate = trim($request->post('death_date', ''));
        $certNumber = trim($request->post('death_certificate_number', ''));
        $notes = trim($request->post('notes', ''));

        if (!$deceasedType || !$deathDate) {
            return $this->redirect("/death/create/{$memberId}")->withError('بيانات الوفاة غير مكتملة');
        }

        $fees = self::getFees();
        $totalFee = $fees['totalFee'];

        $caseData = [
            'member_id'                => (int) $memberId,
            'deceased_type'            => $deceasedType,
            'death_date'               => $deathDate,
            'death_certificate_number' => $certNumber ?: null,
            'same_membership_number'   => ($deceasedType === 'primary_member') ? 1 : 0,
            'fee_amount'               => $totalFee,
            'status'                   => 'recorded',
            'notes'                    => $notes ?: null,
        ];

        if ($deceasedType === 'primary_member') {
            $primarySpouseId = $request->post('primary_spouse_id') ? (int) $request->post('primary_spouse_id') : null;
            $secondarySpouseIds = $request->post('secondary_spouse_ids', []);
            $childrenAssignment = $request->post('children_assignment', []);

            if (!$primarySpouseId) {
                return $this->redirect("/death/create/{$memberId}")->withError('يجب اختيار الزوجة الأساسية لنقل العضوية');
            }

            $caseData['spouse_id'] = $primarySpouseId;
            $caseData['primary_spouse_id'] = $primarySpouseId;
            $caseData['secondary_spouses_json'] = !empty($secondarySpouseIds) ? json_encode(array_map('intval', $secondarySpouseIds)) : null;
            $caseData['children_assignment_json'] = !empty($childrenAssignment) ? json_encode($childrenAssignment) : null;

            // Total fee: 570+annual for primary + 570+annual for each secondary
            $secondaryCount = count($secondarySpouseIds);
            if ($secondaryCount > 0) {
                $totalFee = bcmul($fees['totalFee'], (string) (1 + $secondaryCount), 2);
                $caseData['fee_amount'] = $totalFee;
            }
        } elseif ($deceasedType === 'spouse') {
            $spouseId = $request->post('spouse_id') ? (int) $request->post('spouse_id') : null;
            $caseData['spouse_id'] = $spouseId;
            $caseData['fee_amount'] = '0.00';
        } elseif ($deceasedType === 'child') {
            $childId = $request->post('child_id') ? (int) $request->post('child_id') : null;
            $caseData['child_id'] = $childId;
            $caseData['fee_amount'] = '0.00';
        }

        $case = DeathCase::create($caseData);

        EventBus::dispatch('death.recorded', ['case_id' => (int) $case->id, 'member_id' => (int) $memberId, 'type' => $deceasedType]);

        // Send payment to cashier queue (only for primary_member death which requires transfer fee)
        if (bccomp($totalFee, '0', 2) > 0) {
            $secondaryCount = 0;
            if (!empty($caseData['secondary_spouses_json'])) {
                $secondaryCount = count(json_decode($caseData['secondary_spouses_json'], true));
            }
            $breakdown = [
                'رسوم نقل العضوية للزوجة الأساسية:',
                '  رسوم استمارة (570): ' . money($fees['formFee']),
                '  اشتراك سنوي: ' . money($fees['annualSub']),
            ];
            if ($secondaryCount > 0) {
                $breakdown[] = '';
                $breakdown[] = "رسوم عضويات منفصلة ({$secondaryCount} زوجة إضافية):";
                $breakdown[] = "  {$secondaryCount} × " . money($fees['totalFee']) . ' = ' . money(bcmul($fees['totalFee'], (string) $secondaryCount, 2));
            }
            $breakdown[] = '═══════════════════════════';
            $breakdown[] = 'الإجمالي: ' . money($totalFee);

            $result = PaymentRequestService::createRequest([
                'member_id'           => (int) $memberId,
                'amount'              => $totalFee,
                'payment_type'        => 'death_fee',
                'related_entity_type' => 'death_cases',
                'related_entity_id'   => (int) $case->id,
                'description_ar'      => 'رسوم وفاة — نقل عضوية — حالة #' . $case->id,
                'notes'               => json_encode(['fee_breakdown' => $breakdown], JSON_UNESCAPED_UNICODE),
            ]);

            if ($result['success']) {
                return $this->redirect("/death/{$case->id}")->withSuccess(
                    'تم تسجيل حالة الوفاة وإرسال طلب الدفع للخزينة — ' . money($totalFee)
                );
            }
        }

        return $this->redirect("/death/{$case->id}")->withSuccess('تم تسجيل حالة الوفاة');
    }

    public function show(Request $request, string $id): Response
    {
        $db = App::getInstance()->db();
        $case = $db->selectOne(
            "SELECT dc.*, m.full_name_ar as member_name, m.membership_number
             FROM death_cases dc JOIN members m ON m.id = dc.member_id WHERE dc.id = ?",
            [(int) $id]
        );
        if (!$case) return $this->redirect('/death')->withError('الحالة غير موجودة');

        $fees = self::getFees();
        $primarySpouse = null;
        $secondarySpouses = [];
        $newMember = null;

        if ($case['primary_spouse_id']) {
            $primarySpouse = $db->selectOne("SELECT * FROM spouses WHERE id = ?", [(int) $case['primary_spouse_id']]);
        }
        if (!empty($case['secondary_spouses_json'])) {
            $ids = json_decode($case['secondary_spouses_json'], true);
            if ($ids) {
                $placeholders = implode(',', array_fill(0, count($ids), '?'));
                $secondarySpouses = $db->select("SELECT * FROM spouses WHERE id IN ({$placeholders})", $ids);
            }
        }
        if ($case['transferred_to_member_id']) {
            $newMember = $db->selectOne("SELECT id, full_name_ar, membership_number, status FROM members WHERE id = ?", [(int) $case['transferred_to_member_id']]);
        }

        return $this->view('Death.Views.show', [
            'case'             => $case,
            'fees'             => $fees,
            'primarySpouse'    => $primarySpouse,
            'secondarySpouses' => $secondarySpouses,
            'newMember'        => $newMember,
        ]);
    }

    public function pay(Request $request, string $id): Response
    {
        $db = App::getInstance()->db();
        $case = $db->selectOne("SELECT * FROM death_cases WHERE id = ?", [(int) $id]);
        if (!$case) return $this->redirect('/death')->withError('الحالة غير موجودة');
        if (in_array($case['status'], ['completed', 'fee_paid', 'pending_form_fill'], true)) {
            return $this->redirect("/death/{$id}")->withError('تم دفع الرسوم مسبقاً');
        }

        $amount = $case['fee_amount'] ?? '0.00';
        if (bccomp((string) $amount, '0', 2) <= 0) {
            return $this->redirect("/death/{$id}")->withError('لا توجد رسوم مطلوبة');
        }

        $result = PaymentService::processPayment([
            'member_id'           => (int) $case['member_id'],
            'amount'              => $amount,
            'payment_type'        => 'death_fee',
            'payment_method'      => $request->post('payment_method', 'cash'),
            'related_entity_type' => 'death_cases',
            'related_entity_id'   => (int) $id,
            'description'         => 'رسوم وفاة — حالة #' . $id,
        ]);

        if (!$result['success']) {
            return $this->redirect("/death/{$id}")->withError($result['error']);
        }

        // For primary member death: move to pending_form_fill so wife fills full form
        $newStatus = ($case['deceased_type'] === 'primary_member') ? 'pending_form_fill' : 'fee_paid';

        $db->update('death_cases', [
            'status'     => $newStatus,
            'updated_at' => date('Y-m-d H:i:s'),
        ], '`id` = ?', [(int) $id]);

        EventBus::dispatch('death.fee_paid', ['case_id' => (int) $id, 'payment_id' => $result['payment_id']]);

        if ($newStatus === 'pending_form_fill') {
            return $this->redirect("/death/{$id}")->withSuccess('تم دفع الرسوم — الآن يجب ملء استمارة العضوية الجديدة للزوجة');
        }

        return $this->redirect("/death/{$id}")->withSuccess('تم دفع الرسوم — إيصال: ' . $result['receipt_number']);
    }

    public function fillForm(Request $request, string $id): Response
    {
        $db = App::getInstance()->db();
        $case = $db->selectOne("SELECT * FROM death_cases WHERE id = ?", [(int) $id]);
        if (!$case || $case['status'] !== 'pending_form_fill') {
            return $this->redirect("/death/{$id}")->withError('لا يمكن ملء الاستمارة في هذه المرحلة');
        }

        $spouse = $db->selectOne("SELECT * FROM spouses WHERE id = ?", [(int) $case['primary_spouse_id']]);
        $member = $db->selectOne("SELECT * FROM members WHERE id = ?", [(int) $case['member_id']]);

        return $this->view('Death.Views.form_fill', [
            'case'           => $case,
            'spouse'         => $spouse,
            'member'         => $member,
            'qualifications' => $db->select("SELECT id, name_ar FROM qualifications WHERE is_active = 1 ORDER BY sort_order"),
            'governorates'   => $db->select("SELECT code, name_ar FROM governorates WHERE is_active = 1 ORDER BY name_ar"),
            'countries'      => $db->select("SELECT nationality_ar FROM countries WHERE is_active = 1 ORDER BY name_ar"),
        ]);
    }

    public function saveFillForm(Request $request, string $id): Response
    {
        $db = App::getInstance()->db();
        $case = $db->selectOne("SELECT * FROM death_cases WHERE id = ?", [(int) $id]);
        if (!$case || $case['status'] !== 'pending_form_fill') {
            return $this->redirect("/death/{$id}")->withError('لا يمكن ملء الاستمارة في هذه المرحلة');
        }

        $data = $request->all();
        unset($data['_csrf_token']);

        $requiredFields = ['full_name_ar', 'national_id', 'date_of_birth', 'gender', 'qualification_id'];
        foreach ($requiredFields as $field) {
            if (empty($data[$field])) {
                return $this->redirect("/death/{$id}/fill-form")->withError("الحقل {$field} مطلوب");
            }
        }

        // Store form data in session for completion step
        $db->update('death_cases', [
            'primary_spouse_form_filled' => 1,
            'notes'                      => json_encode(['form_data' => $data], JSON_UNESCAPED_UNICODE),
            'updated_at'                 => date('Y-m-d H:i:s'),
        ], '`id` = ?', [(int) $id]);

        return $this->redirect("/death/{$id}")->withSuccess('تم ملء الاستمارة — يمكن الآن إتمام نقل العضوية');
    }

    public function complete(Request $request, string $id): Response
    {
        $db = App::getInstance()->db();
        $case = $db->selectOne("SELECT * FROM death_cases WHERE id = ?", [(int) $id]);
        if (!$case || $case['status'] === 'completed') return $this->redirect('/death')->withError('الحالة غير صالحة');

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

        $db->beginTransaction();
        try {
            $snapshotId = ArchiveService::takeSnapshot('members', (int) $case['member_id'], 'death', 'وفاة — حالة #' . $id);

            if ($case['deceased_type'] === 'spouse' && $case['spouse_id']) {
                $db->update('spouses', [
                    'status' => 'deceased', 'is_archived' => 1,
                    'archived_at' => date('Y-m-d H:i:s'),
                ], '`id` = ?', [(int) $case['spouse_id']]);

            } elseif ($case['deceased_type'] === 'child' && $case['child_id']) {
                $db->update('children', [
                    'status' => 'deceased', 'is_archived' => 1,
                    'archived_at' => date('Y-m-d H:i:s'),
                ], '`id` = ?', [(int) $case['child_id']]);

            } elseif ($case['deceased_type'] === 'primary_member') {
                if (!$case['primary_spouse_form_filled']) {
                    $db->rollBack();
                    return $this->redirect("/death/{$id}")->withError('يجب ملء استمارة العضوية الجديدة أولاً');
                }

                $member = $db->selectOne("SELECT * FROM members WHERE id = ?", [(int) $case['member_id']]);
                $spouse = $db->selectOne("SELECT * FROM spouses WHERE id = ?", [(int) $case['primary_spouse_id']]);

                $formData = [];
                if (!empty($case['notes'])) {
                    $notesData = json_decode($case['notes'], true);
                    $formData = $notesData['form_data'] ?? [];
                }

                $inheritedNumber = $member['membership_number'];

                // Find the death_fee payment that was made for this case
                $deathPayment = $db->selectOne(
                    "SELECT id FROM payments WHERE member_id = ? AND payment_type = 'death_fee' AND related_entity_type = 'death_cases' AND related_entity_id = ? AND is_voided = 0 ORDER BY id DESC LIMIT 1",
                    [(int) $case['member_id'], (int) $id]
                );
                $deathPaymentId = $deathPayment ? (int) $deathPayment['id'] : null;

                // STEP 1: Archive the deceased member FIRST to release the membership_number
                $db->update('members', [
                    'is_archived'       => 1,
                    'archived_at'       => date('Y-m-d H:i:s'),
                    'status'            => 'deceased',
                    'membership_number' => null,
                ], '`id` = ?', [(int) $case['member_id']]);

                // STEP 2: Now safe to insert the new member with the inherited number
                $newMemberData = [
                    'membership_number'      => $inheritedNumber,
                    'full_name_ar'           => $formData['full_name_ar'] ?? $spouse['full_name_ar'],
                    'full_name_en'           => $formData['full_name_en'] ?? $spouse['full_name_en'] ?? null,
                    'national_id'            => $formData['national_id'] ?? $spouse['national_id'],
                    'date_of_birth'          => $formData['date_of_birth'] ?? $spouse['date_of_birth'],
                    'gender'                 => $formData['gender'] ?? $spouse['gender'],
                    'nationality'            => $formData['nationality'] ?? $spouse['nationality'] ?? 'مصري',
                    'branch_id'              => (int) $member['branch_id'],
                    'membership_type'        => 'working',
                    'member_category'        => 'working_member',
                    'status'                 => 'active',
                    'activated_at'           => date('Y-m-d H:i:s'),
                    'activated_by_payment_id'=> $deathPaymentId,
                    'qualification_id'       => !empty($formData['qualification_id']) ? (int) $formData['qualification_id'] : ($spouse['qualification_id'] ?? $member['qualification_id']),
                    'phone_mobile'           => $formData['phone_mobile'] ?? $spouse['mobile'] ?? $member['phone_mobile'],
                    'membership_value'       => $member['membership_value'],
                    'created_at'             => date('Y-m-d H:i:s'),
                    'updated_at'             => date('Y-m-d H:i:s'),
                    'created_by'             => $employee ? (int) $employee->id : null,
                ];

                $optionalFields = ['marital_status', 'religion', 'phone_home', 'email', 'emergency_name', 'emergency_phone', 'residence_address', 'area', 'governorate', 'occupation', 'job_title'];
                foreach ($optionalFields as $field) {
                    if (!empty($formData[$field])) {
                        $newMemberData[$field] = $formData[$field];
                    }
                }

                $newMemberId = $db->insert('members', $newMemberData);

                // Archive primary spouse record
                $db->update('spouses', [
                    'status' => 'transferred', 'is_archived' => 1,
                    'archived_at' => date('Y-m-d H:i:s'),
                ], '`id` = ?', [(int) $case['primary_spouse_id']]);

                // Handle children assignment
                $childrenAssignment = !empty($case['children_assignment_json']) ? json_decode($case['children_assignment_json'], true) : [];
                if (!empty($childrenAssignment)) {
                    foreach ($childrenAssignment as $childId => $assignTo) {
                        if ($assignTo === 'primary') {
                            $db->update('children', ['member_id' => $newMemberId, 'updated_at' => date('Y-m-d H:i:s')],
                                '`id` = ? AND `is_archived` = 0', [(int) $childId]);
                        }
                    }
                } else {
                    $db->update('children', ['member_id' => $newMemberId, 'updated_at' => date('Y-m-d H:i:s')],
                        '`member_id` = ? AND `is_archived` = 0', [(int) $case['member_id']]);
                }

                // Handle secondary spouses — create separate new memberships with NEW numbers
                if (!empty($case['secondary_spouses_json'])) {
                    $secondaryIds = json_decode($case['secondary_spouses_json'], true);
                    foreach ($secondaryIds as $secSpouseId) {
                        $secSpouse = $db->selectOne("SELECT * FROM spouses WHERE id = ?", [(int) $secSpouseId]);
                        if (!$secSpouse) continue;

                        $secMemberId = $db->insert('members', [
                            'full_name_ar'           => $secSpouse['full_name_ar'],
                            'full_name_en'           => $secSpouse['full_name_en'] ?? null,
                            'national_id'            => $secSpouse['national_id'],
                            'date_of_birth'          => $secSpouse['date_of_birth'],
                            'gender'                 => $secSpouse['gender'],
                            'nationality'            => $secSpouse['nationality'] ?? 'مصري',
                            'branch_id'              => (int) $member['branch_id'],
                            'membership_type'        => 'working',
                            'member_category'        => 'working_member',
                            'status'                 => 'active',
                            'activated_at'           => date('Y-m-d H:i:s'),
                            'activated_by_payment_id'=> $deathPaymentId,
                            'phone_mobile'           => $secSpouse['mobile'] ?? null,
                            'membership_value'       => $member['membership_value'],
                            'created_at'             => date('Y-m-d H:i:s'),
                            'updated_at'             => date('Y-m-d H:i:s'),
                            'created_by'             => $employee ? (int) $employee->id : null,
                        ]);

                        \App\Modules\Members\Services\MemberNumberGenerator::assign($secMemberId);

                        $db->update('spouses', [
                            'status' => 'transferred', 'is_archived' => 1,
                            'archived_at' => date('Y-m-d H:i:s'),
                        ], '`id` = ?', [(int) $secSpouseId]);

                        // Move children assigned to this secondary spouse
                        if (!empty($childrenAssignment)) {
                            foreach ($childrenAssignment as $childId => $assignTo) {
                                if ((int) $assignTo === (int) $secSpouseId) {
                                    $db->update('children', ['member_id' => $secMemberId, 'updated_at' => date('Y-m-d H:i:s')],
                                        '`id` = ? AND `is_archived` = 0', [(int) $childId]);
                                }
                            }
                        }
                    }
                }

                // Transfer temporary_members to new primary
                $db->update('temporary_members', ['member_id' => $newMemberId, 'updated_at' => date('Y-m-d H:i:s')],
                    '`member_id` = ? AND `is_archived` = 0', [(int) $case['member_id']]);

                ArchiveService::recordNumberTransfer($inheritedNumber, 'death_transfer', 'members', $newMemberId);

                $db->update('death_cases', [
                    'transferred_to_member_id' => $newMemberId,
                    'archive_snapshot_id'      => $snapshotId,
                    'status'                   => 'completed',
                    'updated_at'               => date('Y-m-d H:i:s'),
                ], '`id` = ?', [(int) $id]);

                $db->commit();
                EventBus::dispatch('death.completed', ['case_id' => (int) $id, 'new_member_id' => $newMemberId]);
                return $this->redirect("/death/{$id}")->withSuccess('تم نقل العضوية بنفس الرقم — رقم العضوية: ' . $inheritedNumber);
            }

            // Non-primary-member death (spouse or child)
            $db->update('death_cases', [
                'archive_snapshot_id' => $snapshotId,
                'status'              => 'completed',
                'updated_at'          => date('Y-m-d H:i:s'),
            ], '`id` = ?', [(int) $id]);

            $db->commit();
            return $this->redirect("/death/{$id}")->withSuccess('تم إتمام حالة الوفاة');
        } catch (\Throwable $e) {
            $db->rollBack();
            return $this->redirect("/death/{$id}")->withError('فشل: ' . $e->getMessage());
        }
    }
}
