<?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\Core\Logger;
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\Members\Services\NationalIdParser;
use App\Modules\ServiceCatalog\Models\ServicePrice;

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');
    }

    /**
     * Calculate full annual subscription for all family members of a membership.
     */
    private static function calculateFamilyAnnualSub(int $memberId): array
    {
        $db = App::getInstance()->db();
        $memberSub = ServicePrice::getPrice('SVC_ANNUAL_MEMBER', '492.00');
        $spouseSub = ServicePrice::getPrice('SVC_ANNUAL_SPOUSE', '492.00');
        $childSub  = ServicePrice::getPrice('SVC_ANNUAL_CHILD', '222.00');
        $tempSub   = ServicePrice::getPrice('SVC_ANNUAL_TEMP', '222.00');
        $devFeeData = RuleEngine::get('DEVELOPMENT_FEE');
        $devFee = $devFeeData['amount'] ?? '35.00';

        $spouseCount = (int) ($db->selectOne(
            "SELECT COUNT(*) as cnt FROM spouses WHERE member_id = ? AND is_archived = 0 AND status = 'active'",
            [$memberId]
        )['cnt'] ?? 0);
        $childCount = (int) ($db->selectOne(
            "SELECT COUNT(*) as cnt FROM children WHERE member_id = ? AND is_archived = 0 AND status = 'active'",
            [$memberId]
        )['cnt'] ?? 0);
        $tempCount = (int) ($db->selectOne(
            "SELECT COUNT(*) as cnt FROM temporary_members WHERE member_id = ? AND is_archived = 0 AND status = 'active'",
            [$memberId]
        )['cnt'] ?? 0);

        $familyTotal = $memberSub;
        $familyTotal = bcadd($familyTotal, bcmul($spouseSub, (string) $spouseCount, 2), 2);
        $familyTotal = bcadd($familyTotal, bcmul($childSub, (string) $childCount, 2), 2);
        $familyTotal = bcadd($familyTotal, bcmul($tempSub, (string) $tempCount, 2), 2);
        $annualSubTotal = bcadd($familyTotal, $devFee, 2);

        return [
            'annual_sub_total' => $annualSubTotal,
            'member_sub'       => $memberSub,
            'spouse_sub'       => $spouseSub,
            'child_sub'        => $childSub,
            'temp_sub'         => $tempSub,
            'dev_fee'          => $devFee,
            'spouse_count'     => $spouseCount,
            'child_count'      => $childCount,
            'temp_count'       => $tempCount,
        ];
    }

    private static function uploadDocument(array $fileInfo, string $prefix, int $memberId): array
    {
        $allowedMimes = ['application/pdf', 'image/jpeg', 'image/png', 'image/gif'];
        $allowedExts  = ['pdf', 'jpg', 'jpeg', 'png', 'gif'];

        if (empty($fileInfo['tmp_name']) || $fileInfo['error'] !== UPLOAD_ERR_OK) {
            $errMap = [
                UPLOAD_ERR_INI_SIZE   => 'حجم الملف أكبر من المسموح',
                UPLOAD_ERR_FORM_SIZE  => 'حجم الملف أكبر من المسموح',
                UPLOAD_ERR_PARTIAL    => 'رُفع الملف جزئياً',
                UPLOAD_ERR_NO_FILE    => 'لم يتم اختيار ملف',
                UPLOAD_ERR_NO_TMP_DIR => 'مجلد مؤقت غير موجود',
                UPLOAD_ERR_CANT_WRITE => 'فشل كتابة الملف',
                UPLOAD_ERR_EXTENSION  => 'نوع الملف غير مسموح',
            ];
            return ['success' => false, 'error' => $errMap[$fileInfo['error'] ?? UPLOAD_ERR_NO_FILE] ?? 'خطأ في رفع الملف'];
        }

        $finfo = new \finfo(FILEINFO_MIME_TYPE);
        $mime  = $finfo->file($fileInfo['tmp_name']);
        if (!in_array($mime, $allowedMimes, true)) {
            return ['success' => false, 'error' => 'نوع الملف غير مسموح — يجب أن يكون PDF أو صورة (JPG/PNG)'];
        }

        $ext = strtolower(pathinfo($fileInfo['name'], PATHINFO_EXTENSION));
        if (!in_array($ext, $allowedExts, true)) {
            return ['success' => false, 'error' => 'امتداد الملف غير مسموح'];
        }

        $uploadDir = App::getInstance()->basePath() . '/storage/uploads/death/';
        if (!is_dir($uploadDir)) {
            mkdir($uploadDir, 0755, true);
        }

        $filename = $prefix . '_' . $memberId . '_' . time() . '_' . bin2hex(random_bytes(2)) . '.' . $ext;
        $destPath = $uploadDir . $filename;

        if (!move_uploaded_file($fileInfo['tmp_name'], $destPath)) {
            return ['success' => false, 'error' => 'فشل حفظ الملف على الخادم'];
        }

        return ['success' => true, 'path' => 'storage/uploads/death/' . $filename];
    }

    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]);
        $temps = $db->select("SELECT * FROM temporary_members WHERE member_id = ? AND is_archived = 0 AND status = 'active' ORDER BY id", [(int) $memberId]);
        $fees = self::getFees();
        $familySub = self::calculateFamilyAnnualSub((int) $memberId);

        return $this->view('Death.Views.create', [
            'member'     => $member,
            'spouses'    => $spouses,
            'children'   => $children,
            'temps'      => $temps,
            'form_fee'   => $fees['formFee'],
            'annual_sub' => $familySub['annual_sub_total'],
            'total_fee'  => bcadd($fees['formFee'], $familySub['annual_sub_total'], 2),
            'family_sub' => $familySub,
        ]);
    }

    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('بيانات الوفاة غير مكتملة');
        }

        $certPath = null;
        $inheritancePath = null;
        if ($deceasedType === 'primary_member') {
            if (empty($_FILES['death_certificate']['tmp_name'])) {
                return $this->redirect("/death/create/{$memberId}")->withError('يجب رفع شهادة الوفاة (PDF أو صورة)');
            }
            if (empty($_FILES['inheritance_notice']['tmp_name'])) {
                return $this->redirect("/death/create/{$memberId}")->withError('يجب رفع إعلام الوراثة (PDF أو صورة)');
            }

            $certUpload = self::uploadDocument($_FILES['death_certificate'], 'cert', (int) $memberId);
            if (!$certUpload['success']) {
                return $this->redirect("/death/create/{$memberId}")->withError('شهادة الوفاة: ' . $certUpload['error']);
            }

            $inheritanceUpload = self::uploadDocument($_FILES['inheritance_notice'], 'inh', (int) $memberId);
            if (!$inheritanceUpload['success']) {
                return $this->redirect("/death/create/{$memberId}")->withError('إعلام الوراثة: ' . $inheritanceUpload['error']);
            }

            $certPath        = $certUpload['path'];
            $inheritancePath = $inheritanceUpload['path'];
        }

        $fees = self::getFees();
        $familySub = self::calculateFamilyAnnualSub((int) $memberId);
        $totalFee = bcadd($fees['formFee'], $familySub['annual_sub_total'], 2);

        $initialStatus = ($deceasedType === 'primary_member') ? 'board_review' : 'recorded';

        $caseData = [
            'member_id'                => (int) $memberId,
            'deceased_type'            => $deceasedType,
            'death_date'               => $deathDate,
            'death_certificate_number' => $certNumber ?: null,
            'death_certificate_path'   => $certPath,
            'inheritance_notice_path'  => $inheritancePath,
            'same_membership_number'   => ($deceasedType === 'primary_member') ? 1 : 0,
            'fee_amount'               => $totalFee,
            'status'                   => $initialStatus,
            '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', []);
            $tempsAssignment    = $request->post('temps_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;

            // Store temps assignment in notes JSON
            $notesPayload = [];
            if ($notes) $notesPayload['user_notes'] = $notes;
            if (!empty($tempsAssignment)) $notesPayload['temps_assignment'] = $tempsAssignment;
            if (!empty($notesPayload)) {
                $caseData['notes'] = json_encode($notesPayload, JSON_UNESCAPED_UNICODE);
            }

            $secondaryCount = count($secondarySpouseIds);
            if ($secondaryCount > 0) {
                $totalFee = bcmul($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]);

        if ($deceasedType === 'primary_member') {
            return $this->redirect("/death/{$case->id}")->withSuccess('تم تسجيل حالة الوفاة وإرسالها لمراجعة مجلس الإدارة');
        }

        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, m.membership_value as member_membership_value
             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();
        $familySub = self::calculateFamilyAnnualSub((int) $case['member_id']);
        $primarySpouse    = null;
        $secondarySpouses = [];
        $newMember        = null;
        $paymentRequest   = null;
        $boardApprover    = 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']]);
        }
        if ($case['payment_request_id']) {
            $paymentRequest = $db->selectOne("SELECT * FROM payment_requests WHERE id = ?", [(int) $case['payment_request_id']]);
        }
        if ($case['board_approved_by']) {
            $boardApprover = $db->selectOne("SELECT full_name_ar FROM employees WHERE id = ?", [(int) $case['board_approved_by']]);
        }

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

    public function boardApprove(Request $request, string $id): Response
    {
        $this->authorize('transfer.approve');
        $db       = App::getInstance()->db();
        $employee = App::getInstance()->currentEmployee();

        $case = $db->selectOne("SELECT * FROM death_cases WHERE id = ?", [(int) $id]);
        if (!$case) return $this->redirect('/death')->withError('الحالة غير موجودة');
        if ($case['status'] !== 'board_review') {
            return $this->redirect("/death/{$id}")->withError('الحالة ليست في مرحلة مراجعة مجلس الإدارة');
        }

        $feeMethod    = trim($request->post('fee_method', ''));
        $feeValue     = trim($request->post('fee_value', '0'));
        $boardRef     = trim($request->post('board_decision_reference', ''));
        $boardDate    = trim($request->post('board_decision_date', ''));
        $boardNotes   = trim($request->post('board_notes', ''));

        if (!in_array($feeMethod, ['percentage', 'fixed'], true)) {
            return $this->redirect("/death/{$id}")->withError('يجب تحديد طريقة احتساب رسوم مجلس الأمناء');
        }
        if (!is_numeric($feeValue) || bccomp($feeValue, '0', 4) < 0) {
            return $this->redirect("/death/{$id}")->withError('قيمة رسوم مجلس الأمناء غير صحيحة');
        }

        $boardFeeAmount = '0.00';
        if ($feeMethod === 'percentage') {
            $memberRow = $db->selectOne("SELECT membership_value FROM members WHERE id = ?", [(int) $case['member_id']]);
            $membershipValue = (string) ($memberRow['membership_value'] ?? '0');
            $boardFeeAmount = bcdiv(bcmul($membershipValue, $feeValue, 6), '100', 2);
        } else {
            $boardFeeAmount = bcadd($feeValue, '0', 2);
        }

        // Calculate family annual subscription
        $fees = self::getFees();
        $familySub = self::calculateFamilyAnnualSub((int) $case['member_id']);
        $annualSubTotal = $familySub['annual_sub_total'];

        $secondaryCount = 0;
        if (!empty($case['secondary_spouses_json'])) {
            $secondaryCount = count(json_decode($case['secondary_spouses_json'], true));
        }

        // Base fees per membership = form_fee + family annual subscription
        $basePerMembership = bcadd($fees['formFee'], $annualSubTotal, 2);
        $baseFees = bcmul($basePerMembership, (string) (1 + $secondaryCount), 2);
        $totalFee = bcadd($baseFees, $boardFeeAmount, 2);

        $db->update('death_cases', [
            'board_fee_method'         => $feeMethod,
            'board_fee_value'          => $feeValue,
            'board_fee_amount'         => $boardFeeAmount,
            'board_decision_reference' => $boardRef ?: null,
            'board_decision_date'      => $boardDate ?: null,
            'board_notes'              => $boardNotes ?: null,
            'board_approved_by'        => $employee ? (int) $employee->id : null,
            'board_approved_at'        => date('Y-m-d H:i:s'),
            'fee_amount'               => $totalFee,
            'status'                   => 'board_approved',
            'updated_at'               => date('Y-m-d H:i:s'),
        ], '`id` = ?', [(int) $id]);

        // Build fee breakdown
        $multiplierLabel = $secondaryCount > 0 ? " (× " . (1 + $secondaryCount) . " عضويات)" : '';
        $breakdown = [
            'رسوم نقل العضوية' . $multiplierLabel . ':',
            '  رسوم استمارة: ' . money($fees['formFee']),
            '  اشتراك سنوي (جميع الأفراد): ' . money($annualSubTotal),
            '    - العضو: ' . money($familySub['member_sub']),
        ];
        if ($familySub['spouse_count'] > 0) {
            $breakdown[] = '    - ' . $familySub['spouse_count'] . ' زوجة: ' . money(bcmul($familySub['spouse_sub'], (string) $familySub['spouse_count'], 2));
        }
        if ($familySub['child_count'] > 0) {
            $breakdown[] = '    - ' . $familySub['child_count'] . ' أبناء: ' . money(bcmul($familySub['child_sub'], (string) $familySub['child_count'], 2));
        }
        if ($familySub['temp_count'] > 0) {
            $breakdown[] = '    - ' . $familySub['temp_count'] . ' مؤقتين: ' . money(bcmul($familySub['temp_sub'], (string) $familySub['temp_count'], 2));
        }
        $breakdown[] = '    - رسوم تنمية: ' . money($familySub['dev_fee']);
        if ($secondaryCount > 0) {
            $breakdown[] = '  مجموع الأساس (' . (1 + $secondaryCount) . ' عضويات): ' . money($baseFees);
        }
        $trusteeLabel = $feeMethod === 'percentage'
            ? 'رسوم مجلس الأمناء (' . $feeValue . '% من قيمة العضوية)'
            : 'رسوم مجلس الأمناء (مبلغ ثابت)';
        $breakdown[] = $trusteeLabel . ': ' . money($boardFeeAmount);
        $breakdown[] = '═══════════════════════════';
        $breakdown[] = 'الإجمالي: ' . money($totalFee);

        // Payment request uses the PRIMARY SPOUSE name (the person receiving the membership)
        $primarySpouse = $db->selectOne("SELECT full_name_ar FROM spouses WHERE id = ?", [(int) $case['primary_spouse_id']]);
        $recipientName = $primarySpouse['full_name_ar'] ?? 'الزوجة';

        $result = PaymentRequestService::createRequest([
            'member_id'           => (int) $case['member_id'],
            'amount'              => $totalFee,
            'payment_type'        => 'death_fee',
            'related_entity_type' => 'death_cases',
            'related_entity_id'   => (int) $id,
            'description_ar'      => 'رسوم نقل عضوية (وفاة) — باسم: ' . $recipientName . ' — حالة #' . $id,
            'notes'               => json_encode([
                'fee_breakdown'   => $breakdown,
                'recipient_name'  => $recipientName,
                'form_fee'        => $fees['formFee'],
                'annual_sub'      => $annualSubTotal,
                'trustee_fee'     => $boardFeeAmount,
                'trustee_method'  => $feeMethod,
                'multiplier'      => 1 + $secondaryCount,
                'total'           => $totalFee,
            ], JSON_UNESCAPED_UNICODE),
        ]);

        if ($result['success']) {
            $db->update('death_cases', [
                'payment_request_id' => $result['request_id'],
                'updated_at'         => date('Y-m-d H:i:s'),
            ], '`id` = ?', [(int) $id]);
        }

        return $this->redirect("/death/{$id}")->withSuccess(
            'تم اعتماد القضية من مجلس الإدارة — رسوم مجلس الأمناء: ' . money($boardFeeAmount) . ' — الإجمالي: ' . money($totalFee)
        );
    }

    public function boardReject(Request $request, string $id): Response
    {
        $this->authorize('transfer.approve');
        $db       = App::getInstance()->db();
        $employee = App::getInstance()->currentEmployee();

        $case = $db->selectOne("SELECT id, status FROM death_cases WHERE id = ?", [(int) $id]);
        if (!$case) return $this->redirect('/death')->withError('الحالة غير موجودة');
        if ($case['status'] !== 'board_review') {
            return $this->redirect("/death/{$id}")->withError('الحالة ليست في مرحلة مراجعة مجلس الإدارة');
        }

        $boardNotes = trim($request->post('board_notes', ''));

        $db->update('death_cases', [
            'status'           => 'rejected',
            'board_notes'      => $boardNotes ?: null,
            'board_approved_by'=> $employee ? (int) $employee->id : null,
            'board_approved_at'=> date('Y-m-d H:i:s'),
            'updated_at'       => date('Y-m-d H:i:s'),
        ], '`id` = ?', [(int) $id]);

        return $this->redirect("/death/{$id}")->withWarning('تم رفض القضية من مجلس الإدارة');
    }

    public function downloadDocument(Request $request, string $id, string $type): Response
    {
        $this->authorize('transfer.view');
        $db = App::getInstance()->db();

        $case = $db->selectOne("SELECT death_certificate_path, inheritance_notice_path FROM death_cases WHERE id = ?", [(int) $id]);
        if (!$case) return $this->redirect('/death')->withError('الحالة غير موجودة');

        $column = match($type) {
            'cert'        => 'death_certificate_path',
            'inheritance' => 'inheritance_notice_path',
            default       => null,
        };

        if (!$column || empty($case[$column])) {
            return $this->redirect("/death/{$id}")->withError('المستند غير موجود');
        }

        $filePath = App::getInstance()->basePath() . '/' . $case[$column];
        if (!file_exists($filePath)) {
            return $this->redirect("/death/{$id}")->withError('ملف المستند غير موجود على الخادم');
        }

        $finfo    = new \finfo(FILEINFO_MIME_TYPE);
        $mime     = $finfo->file($filePath) ?: 'application/octet-stream';
        $filename = basename($filePath);

        header('Content-Type: ' . $mime);
        header('Content-Disposition: inline; filename="' . $filename . '"');
        header('Content-Length: ' . filesize($filePath));
        header('Cache-Control: private, max-age=3600');
        readfile($filePath);
        exit;
    }

    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']);
        }

        $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']);

        $nid = trim((string) ($data['national_id'] ?? ''));
        $data['national_id'] = $nid;
        if ($nid !== '' && strlen($nid) === 14) {
            $parsed = NationalIdParser::parse($nid);
            if ($parsed['is_valid']) {
                $data['date_of_birth'] = $parsed['dob'];
                $data['gender']        = $parsed['gender'];
            }
        }

        $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} مطلوب");
            }
        }

        // Merge with existing notes (temps_assignment etc)
        $existingNotes = !empty($case['notes']) ? json_decode($case['notes'], true) : [];
        if (!is_array($existingNotes)) $existingNotes = [];
        $existingNotes['form_data'] = $data;

        $db->update('death_cases', [
            'primary_spouse_form_filled' => 1,
            'notes'                      => json_encode($existingNotes, 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();

        if ($case['deceased_type'] === 'primary_member') {
            if (!$case['board_approved_at']) {
                return $this->redirect("/death/{$id}")->withError('لم يتم اعتماد القضية من مجلس الإدارة بعد');
            }
            if (!$case['death_certificate_path'] || !$case['inheritance_notice_path']) {
                return $this->redirect("/death/{$id}")->withError('يجب رفع وثيقة الوفاة وإعلام الوراثة قبل الإتمام');
            }
            $deathPaymentCheck = $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",
                [(int) $case['member_id'], (int) $id]
            );
            if (!$deathPaymentCheck) {
                return $this->redirect("/death/{$id}")->withError('لم يتم سداد رسوم الوفاة في الخزينة بعد');
            }
            if (!$case['primary_spouse_form_filled']) {
                return $this->redirect("/death/{$id}")->withError('يجب ملء استمارة العضوية الجديدة للزوجة أولاً');
            }
        }

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

            if ($case['deceased_type'] === 'spouse' && $case['spouse_id']) {
                $spouseRow = $db->selectOne("SELECT full_name_ar FROM spouses WHERE id = ?", [(int) $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']]);
                $auditLog[] = 'تم تسجيل وفاة الزوج/ة: ' . ($spouseRow['full_name_ar'] ?? '');

            } elseif ($case['deceased_type'] === 'child' && $case['child_id']) {
                $childRow = $db->selectOne("SELECT full_name_ar FROM children WHERE id = ?", [(int) $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']]);
                $auditLog[] = 'تم تسجيل وفاة الابن/الابنة: ' . ($childRow['full_name_ar'] ?? '');

            } elseif ($case['deceased_type'] === 'primary_member') {
                $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 = [];
                $notesData = !empty($case['notes']) ? json_decode($case['notes'], true) : [];
                if (is_array($notesData)) {
                    $formData = $notesData['form_data'] ?? [];
                }
                $tempsAssignment = $notesData['temps_assignment'] ?? [];

                $inheritedNumber = $member['membership_number'];
                $auditLog[] = 'العضو المتوفى: ' . $member['full_name_ar'] . ' — رقم العضوية: ' . $inheritedNumber;

                $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 deceased member
                $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: Create new primary member
                $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'] ?? '1900-01-01',
                    'gender'                     => $formData['gender'] ?? $spouse['gender'] ?? 'female',
                    'nationality'                => $formData['nationality'] ?? $spouse['nationality'] ?? 'مصري',
                    'branch_id'                  => (int) $member['branch_id'],
                    'membership_type'            => $member['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'],
                    'transferred_from_death_id'  => (int) $id,
                    'original_membership_number' => $inheritedNumber,
                    'form_number'                => $formData['form_number'] ?? null,
                    'deceased_member_name'       => $member['full_name_ar'],
                    '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);
                $auditLog[] = 'تم تحويل العضوية إلى: ' . ($formData['full_name_ar'] ?? $spouse['full_name_ar']) . ' — رقم العضوية: ' . $inheritedNumber;

                // Archive primary spouse
                $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) : [];
                $childrenMoved = [];
                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]);
                            $childRow = $db->selectOne("SELECT full_name_ar FROM children WHERE id = ?", [(int) $childId]);
                            if ($childRow) $childrenMoved[] = $childRow['full_name_ar'];
                        }
                    }
                } 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']]);
                }

                if (!empty($childrenMoved)) {
                    $auditLog[] = 'تم نقل الأبناء التاليين إلى العضوية الجديدة: ' . implode('، ', $childrenMoved);
                } elseif (empty($childrenAssignment)) {
                    $auditLog[] = 'تم نقل جميع الأبناء إلى العضوية الجديدة';
                }

                // Handle secondary spouses
                $secondaryMemberIds = [];
                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'] ?? '1900-01-01',
                            'gender'                     => $secSpouse['gender'] ?? 'female',
                            'nationality'                => $secSpouse['nationality'] ?? 'مصري',
                            'branch_id'                  => (int) $member['branch_id'],
                            'membership_type'            => $member['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'],
                            'transferred_from_death_id'  => (int) $id,
                            'deceased_member_name'       => $member['full_name_ar'],
                            '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);
                        $secondaryMemberIds[(int) $secSpouseId] = $secMemberId;

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

                        $secNumber = $db->selectOne("SELECT membership_number FROM members WHERE id = ?", [$secMemberId]);
                        $auditLog[] = 'تم إنشاء عضوية منفصلة للزوجة: ' . $secSpouse['full_name_ar'] . ' — رقم: ' . ($secNumber['membership_number'] ?? '');

                        // 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]);
                                    $childRow = $db->selectOne("SELECT full_name_ar FROM children WHERE id = ?", [(int) $childId]);
                                    if ($childRow) {
                                        $auditLog[] = 'تم نقل ' . $childRow['full_name_ar'] . ' إلى عضوية ' . $secSpouse['full_name_ar'];
                                    }
                                }
                            }
                        }
                    }
                }

                // Sweep remaining children to primary
                $db->query(
                    "UPDATE children SET member_id = ?, updated_at = ? WHERE member_id = ? AND is_archived = 0",
                    [$newMemberId, date('Y-m-d H:i:s'), (int) $case['member_id']]
                );

                // Renumber child_order
                $allChildren = $db->select(
                    "SELECT id FROM children WHERE member_id = ? AND is_archived = 0 ORDER BY child_order, id",
                    [$newMemberId]
                );
                foreach ($allChildren as $i => $c) {
                    $db->update('children', [
                        'child_order'             => $i + 1,
                        'activated_by_payment_id' => $deathPaymentId,
                        'updated_at'              => date('Y-m-d H:i:s'),
                    ], '`id` = ?', [(int) $c['id']]);
                }

                // Transfer temporary members based on assignment
                $tempsMoved = [];
                if (!empty($tempsAssignment)) {
                    foreach ($tempsAssignment as $tempId => $assignTo) {
                        $targetMemberId = $newMemberId;
                        if ($assignTo !== 'primary' && isset($secondaryMemberIds[(int) $assignTo])) {
                            $targetMemberId = $secondaryMemberIds[(int) $assignTo];
                        }
                        $db->update('temporary_members', ['member_id' => $targetMemberId, 'updated_at' => date('Y-m-d H:i:s')],
                            '`id` = ? AND `is_archived` = 0', [(int) $tempId]);
                        $tempRow = $db->selectOne("SELECT full_name_ar FROM temporary_members WHERE id = ?", [(int) $tempId]);
                        if ($tempRow) $tempsMoved[] = $tempRow['full_name_ar'];
                    }
                }
                // Sweep remaining temps to primary
                $db->query(
                    "UPDATE temporary_members SET member_id = ?, updated_at = ? WHERE member_id = ? AND is_archived = 0",
                    [$newMemberId, date('Y-m-d H:i:s'), (int) $case['member_id']]
                );

                if (!empty($tempsMoved)) {
                    $auditLog[] = 'تم نقل الأعضاء المؤقتين: ' . implode('، ', $tempsMoved);
                } else {
                    $tempCount = (int) ($db->selectOne("SELECT COUNT(*) as cnt FROM temporary_members WHERE member_id = ? AND is_archived = 0", [$newMemberId])['cnt'] ?? 0);
                    if ($tempCount > 0) {
                        $auditLog[] = 'تم نقل ' . $tempCount . ' عضو مؤقت إلى العضوية الجديدة';
                    }
                }

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

                $auditLog[] = 'تاريخ التنفيذ: ' . date('Y-m-d H:i:s');
                $auditLog[] = 'بواسطة: ' . ($employee ? $employee->full_name_ar : 'النظام');
                $auditLog[] = 'تم إنشاء العضوية الجديدة بعد اعتماد السداد من الخزينة';

                // Store audit log in notes (merge with existing)
                $finalNotes = !empty($case['notes']) ? json_decode($case['notes'], true) : [];
                if (!is_array($finalNotes)) $finalNotes = [];
                $finalNotes['audit_log'] = $auditLog;

                $db->update('death_cases', [
                    'transferred_to_member_id' => $newMemberId,
                    'archive_snapshot_id'      => $snapshotId,
                    'status'                   => 'completed',
                    'notes'                    => json_encode($finalNotes, JSON_UNESCAPED_UNICODE),
                    '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]);
                Logger::info("Death case #{$id} completed", ['new_member' => $newMemberId, 'audit' => $auditLog]);

                return $this->redirect("/death/{$id}")->withSuccess('تم نقل العضوية بنفس الرقم — رقم العضوية: ' . $inheritedNumber);
            }

            // Non-primary-member death
            $auditLog[] = 'تاريخ التنفيذ: ' . date('Y-m-d H:i:s');
            $auditLog[] = 'بواسطة: ' . ($employee ? $employee->full_name_ar : 'النظام');

            $finalNotes = !empty($case['notes']) ? json_decode($case['notes'], true) : [];
            if (!is_array($finalNotes)) $finalNotes = [];
            $finalNotes['audit_log'] = $auditLog;

            $db->update('death_cases', [
                'archive_snapshot_id' => $snapshotId,
                'status'              => 'completed',
                'notes'               => json_encode($finalNotes, JSON_UNESCAPED_UNICODE),
                '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();
            Logger::error("Death case #{$id} failed: " . $e->getMessage());
            return $this->redirect("/death/{$id}")->withError('فشل: ' . $e->getMessage());
        }
    }
}
