<?php
declare(strict_types=1);

namespace App\Modules\Waiver\Controllers;

use App\Core\Controller;
use App\Core\Request;
use App\Core\Response;
use App\Core\App;
use App\Core\EventBus;
use App\Modules\Waiver\Models\WaiverRequest;
use App\Modules\Waiver\Services\WaiverProcessor;
use App\Modules\Rules\Services\RuleEngine;
use App\Modules\Payments\Services\PaymentService;
use App\Modules\Cashier\Services\PaymentRequestService;

class WaiverController extends Controller
{
    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 = WaiverRequest::search($filters, 25, $page);
        return $this->view('Waiver.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('العضو غير موجود');

        $membershipValue = self::getCurrentMembershipValue($db, $member);
        $waiverPctData = RuleEngine::get('WAIVER_FEE');
        $waiverPct = $waiverPctData['percentage'] ?? '30.00';
        $waiverFee = bcdiv(bcmul($membershipValue, $waiverPct, 4), '100', 2);

        $dependents = WaiverProcessor::countDependents((int) $memberId);
        $dependentDetails = WaiverProcessor::getDependentDetails((int) $memberId);
        $debtCheck = WaiverProcessor::checkDebtsComprehensive((int) $memberId);

        return $this->view('Waiver.Views.create', [
            'member'             => $member,
            'membership_value'   => $membershipValue,
            'waiver_pct'         => $waiverPct,
            'waiver_fee'         => $waiverFee,
            'dependents'         => $dependents,
            'dependent_details'  => $dependentDetails,
            'total_dependents'   => $dependents['total'],
            'debt_check'         => $debtCheck,
        ]);
    }

    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('العضو غير موجود');
        if (!$member['membership_number']) return $this->redirect("/members/{$memberId}")->withError('العضو ليس لديه رقم عضوية');

        // Check debts on source member (including dependents)
        $debtCheck = WaiverProcessor::checkDebtsComprehensive((int) $memberId);
        if (!$debtCheck['clear']) {
            return $this->redirect("/members/{$memberId}")->withError(
                'لا يمكن تقديم طلب التنازل — يوجد مديونية على المتنازل بمبلغ ' . money($debtCheck['total']) . ' يجب سدادها أولاً'
            );
        }

        // Check debts on target member if specified (including dependents)
        $targetMemberId = (int) $request->post('target_member_id', 0);
        if ($targetMemberId > 0) {
            $targetDebtCheck = WaiverProcessor::checkDebtsComprehensive($targetMemberId);
            if (!$targetDebtCheck['clear']) {
                return $this->redirect("/members/{$memberId}")->withError(
                    'لا يمكن تقديم طلب التنازل — يوجد مديونية على المتنازل إليه بمبلغ ' . money($targetDebtCheck['total']) . ' يجب سدادها أولاً'
                );
            }
        }

        $membershipValue = self::getCurrentMembershipValue($db, $member);
        $waiverPctData = RuleEngine::get('WAIVER_FEE');
        $waiverPct = $waiverPctData['percentage'] ?? '30.00';
        $waiverFee = bcdiv(bcmul($membershipValue, $waiverPct, 4), '100', 2);

        $dependents = WaiverProcessor::countDependents((int) $memberId);

        // Handle document uploads
        $waiverDocPath = null;
        $targetFormPath = null;
        $uploadDir = 'uploads/waivers/' . date('Y/m');

        if (!empty($_FILES['waiver_request_doc']['tmp_name'])) {
            $waiverDocPath = self::handleUpload($_FILES['waiver_request_doc'], $uploadDir, 'waiver_req_' . $memberId);
        }
        if (!empty($_FILES['target_form_doc']['tmp_name'])) {
            $targetFormPath = self::handleUpload($_FILES['target_form_doc'], $uploadDir, 'target_form_' . $memberId);
        }

        $waiver = WaiverRequest::create([
            'source_member_id'           => (int) $memberId,
            'target_member_id'           => $targetMemberId > 0 ? $targetMemberId : null,
            'membership_number'          => $member['membership_number'],
            'form_number'                => trim($request->post('form_number', '')) ?: null,
            'membership_value_at_waiver' => $membershipValue,
            'waiver_fee_percentage'      => $waiverPct,
            'waiver_fee_amount'          => $waiverFee,
            'original_dependent_count'   => $dependents['total'],
            'original_spouses_count'     => $dependents['spouses'],
            'original_children_count'    => $dependents['children'],
            'original_temporary_count'   => $dependents['temporary'],
            'board_approval_required'    => 1,
            'annual_renewal_paid'        => 1,
            'debts_cleared'              => 1,
            'target_debts_cleared'       => $targetMemberId > 0 ? 1 : 0,
            'status'                     => 'requested',
            'notes'                      => trim($request->post('notes', '')) ?: null,
            'waiver_request_doc_path'    => $waiverDocPath,
            'target_form_doc_path'       => $targetFormPath,
        ]);

        EventBus::dispatch('waiver.requested', ['waiver_id' => (int) $waiver->id, 'member_id' => (int) $memberId]);

        return $this->redirect("/waivers/{$waiver->id}")->withSuccess(
            'تم تقديم طلب التنازل بنجاح — في انتظار اعتماد مجلس الأمناء وتحديد الرسوم'
        );
    }

    public function show(Request $request, string $id): Response
    {
        $db = App::getInstance()->db();
        $waiver = $db->selectOne(
            "SELECT wr.*, m.full_name_ar as source_name, m.membership_number as current_source_number,
                    tm.full_name_ar as target_name, e.full_name_ar as approved_by_name
             FROM waiver_requests wr JOIN members m ON m.id = wr.source_member_id
             LEFT JOIN members tm ON tm.id = wr.target_member_id
             LEFT JOIN employees e ON e.id = wr.approved_by
             WHERE wr.id = ?",
            [(int) $id]
        );
        if (!$waiver) return $this->redirect('/waivers')->withError('الطلب غير موجود');

        $sourceDeps = WaiverProcessor::countDependents((int) $waiver['source_member_id']);
        $targetDeps = $waiver['target_member_id'] ? WaiverProcessor::countDependents((int) $waiver['target_member_id']) : null;

        // Detailed dependent data
        $sourceDetails = WaiverProcessor::getDependentDetails((int) $waiver['source_member_id']);
        $targetDetails = $waiver['target_member_id'] ? WaiverProcessor::getDependentDetails((int) $waiver['target_member_id']) : null;

        $originalDeps = [
            'spouses' => (int) ($waiver['original_spouses_count'] ?? $sourceDeps['spouses']),
            'children' => (int) ($waiver['original_children_count'] ?? $sourceDeps['children']),
            'temporary' => (int) ($waiver['original_temporary_count'] ?? $sourceDeps['temporary']),
            'total' => (int) ($waiver['original_dependent_count'] ?? $sourceDeps['total']),
        ];

        $comparison = null;
        if ($targetDeps) {
            $comparison = WaiverProcessor::compareDependents($originalDeps, $targetDeps);
        }

        // Comprehensive debt check for both members (live)
        $sourceDebtCheck = WaiverProcessor::checkDebtsComprehensive((int) $waiver['source_member_id']);
        $targetDebtCheck = $waiver['target_member_id'] ? WaiverProcessor::checkDebtsComprehensive((int) $waiver['target_member_id']) : null;

        // ALL target dependents for board fee assignment (board sees everyone, decides per-person)
        $allTargetDependents = [];
        if ($waiver['target_member_id']) {
            $allTargetDependents = WaiverProcessor::getAllTargetDependents((int) $waiver['target_member_id'], $originalDeps);
        }

        // Already-saved individual fees
        $individualFees = WaiverProcessor::getIndividualFees((int) $id);

        // Payment request tracking
        $paymentRequest = null;
        if (!empty($waiver['target_member_id'])) {
            $paymentRequest = $db->selectOne(
                "SELECT id, request_number, status, amount, created_at FROM payment_requests WHERE related_entity_type = 'waiver_requests' AND related_entity_id = ? AND is_voided = 0 ORDER BY id DESC LIMIT 1",
                [(int) $id]
            );
        }

        return $this->view('Waiver.Views.show', [
            'waiver'                => $waiver,
            'source_deps'           => $sourceDeps,
            'target_deps'           => $targetDeps,
            'source_details'        => $sourceDetails,
            'target_details'        => $targetDetails,
            'original_deps'         => $originalDeps,
            'comparison'            => $comparison,
            'source_debt_check'     => $sourceDebtCheck,
            'target_debt_check'     => $targetDebtCheck,
            'all_target_dependents' => $allTargetDependents,
            'individual_fees'       => $individualFees,
            'paymentRequest'        => $paymentRequest,
        ]);
    }

    public function approve(Request $request, string $id): Response
    {
        $db = App::getInstance()->db();
        $waiver = $db->selectOne("SELECT * FROM waiver_requests WHERE id = ? AND status = 'requested'", [(int) $id]);
        if (!$waiver) return $this->redirect('/waivers')->withError('الطلب غير صالح');

        $employee = App::getInstance()->currentEmployee();
        $boardRef = trim($request->post('board_decision_reference', ''));
        $membershipValue = (string) $waiver['membership_value_at_waiver'];

        $originalDeps = [
            'spouses' => (int) ($waiver['original_spouses_count'] ?? 0),
            'children' => (int) ($waiver['original_children_count'] ?? 0),
            'temporary' => (int) ($waiver['original_temporary_count'] ?? 0),
        ];

        $excessSpouses = 0;
        $excessChildren = 0;
        $excessTemporary = 0;
        $spouseFeeTotal = '0.00';
        $childFeeTotal = '0.00';
        $tempFeeTotal = '0.00';

        if ($waiver['target_member_id']) {
            $targetDeps = WaiverProcessor::countDependents((int) $waiver['target_member_id']);
            $comparison = WaiverProcessor::compareDependents($originalDeps, $targetDeps);
            $excessSpouses = $comparison['excess_spouses'];
            $excessChildren = $comparison['excess_children'];
            $excessTemporary = $comparison['excess_temporary'];

            // Collect per-individual fees from form (arrays indexed by person key)
            $feeTypes = $request->post('ind_fee_type', []);
            $feeRates = $request->post('ind_fee_rate', []);
            $personTypes = $request->post('ind_person_type', []);
            $personIds = $request->post('ind_person_id', []);
            $personNames = $request->post('ind_person_name', []);
            $personOrders = $request->post('ind_person_order', []);
            $personAges = $request->post('ind_age_years', []);
            $personAgeCodes = $request->post('ind_age_category_code', []);
            $personDobs = $request->post('ind_date_of_birth', []);
            $personRelations = $request->post('ind_relationship', []);
            $personStatuses = $request->post('ind_status', []);

            $feesData = [];
            if (is_array($feeTypes)) {
                foreach ($feeTypes as $idx => $fType) {
                    $feesData[] = [
                        'person_type' => $personTypes[$idx] ?? '',
                        'person_id' => (int) ($personIds[$idx] ?? 0),
                        'person_name' => $personNames[$idx] ?? '',
                        'person_order' => (int) ($personOrders[$idx] ?? 1),
                        'fee_type' => $fType ?: null,
                        'fee_rate' => $feeRates[$idx] ?? '0',
                        'age_years' => ($personAges[$idx] ?? '') !== '' ? (int) $personAges[$idx] : null,
                        'age_category_code' => $personAgeCodes[$idx] ?? null,
                        'date_of_birth' => $personDobs[$idx] ?? null,
                        'relationship' => $personRelations[$idx] ?? null,
                        'status' => $personStatuses[$idx] ?? null,
                    ];
                }
            }

            if (!empty($feesData)) {
                $totals = WaiverProcessor::saveIndividualFees((int) $id, $feesData, $membershipValue);
                $spouseFeeTotal = $totals['spouse_total'];
                $childFeeTotal = $totals['child_total'];
                $tempFeeTotal = $totals['temporary_total'];
            }
        }

        $totalExcessFee = bcadd(bcadd($spouseFeeTotal, $childFeeTotal, 2), $tempFeeTotal, 2);
        $totalExcessCount = $excessSpouses + $excessChildren + $excessTemporary;

        $updateData = [
            'status'                   => 'approved',
            'approved_by'              => $employee ? (int) $employee->id : null,
            'approved_at'              => date('Y-m-d H:i:s'),
            'board_decision_reference' => $boardRef ?: null,
            'excess_dependent_count'   => $totalExcessCount,
            'excess_spouses_count'     => $excessSpouses,
            'excess_children_count'    => $excessChildren,
            'excess_temporary_count'   => $excessTemporary,
            'excess_fee_percentage'    => null,
            'excess_fee_amount'        => $totalExcessFee,
            'spouse_fee_total'         => $spouseFeeTotal,
            'child_fee_total'          => $childFeeTotal,
            'temporary_fee_total'      => $tempFeeTotal,
            'updated_at'               => date('Y-m-d H:i:s'),
        ];

        $db->update('waiver_requests', $updateData, '`id` = ?', [(int) $id]);

        $msg = 'تمت الموافقة على طلب التنازل';
        if ($totalExcessCount > 0) {
            $parts = [];
            if ($excessSpouses > 0) $parts[] = $excessSpouses . ' زوجة';
            if ($excessChildren > 0) $parts[] = $excessChildren . ' ابن';
            if ($excessTemporary > 0) $parts[] = $excessTemporary . ' مؤقت';
            $msg .= ' — رسوم إضافية عن: ' . implode(' + ', $parts) . ' = ' . money($totalExcessFee);
        }

        return $this->redirect("/waivers/{$id}")->withSuccess($msg);
    }

    public function reject(Request $request, string $id): Response
    {
        $db = App::getInstance()->db();
        $waiver = $db->selectOne("SELECT * FROM waiver_requests WHERE id = ? AND status = 'requested'", [(int) $id]);
        if (!$waiver) return $this->redirect('/waivers')->withError('الطلب غير صالح');

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

        $db->update('waiver_requests', [
            'status'       => 'rejected',
            'approved_by'  => $employee ? (int) $employee->id : null,
            'approved_at'  => date('Y-m-d H:i:s'),
            'notes'        => trim($request->post('rejection_reason', '')) ?: ($waiver['notes'] ?? null),
            'updated_at'   => date('Y-m-d H:i:s'),
        ], '`id` = ?', [(int) $id]);

        return $this->redirect('/waivers')->withSuccess('تم رفض طلب التنازل');
    }

    /**
     * Send to cashier — creates payment request in TARGET member's name (buyer pays).
     */
    public function sendToCashier(Request $request, string $id): Response
    {
        $db = App::getInstance()->db();
        $waiver = $db->selectOne("SELECT * FROM waiver_requests WHERE id = ? AND status = 'approved'", [(int) $id]);
        if (!$waiver) return $this->redirect("/waivers/{$id}")->withError('الطلب غير صالح أو لم يتم اعتماده');

        if (!$waiver['target_member_id']) {
            return $this->redirect("/waivers/{$id}")->withError('يجب تحديد المتنازل إليه أولاً');
        }

        // Calculate total fee
        $waiverFee = $waiver['waiver_fee_amount'] ?? '0.00';
        $spouseFeeTotal = $waiver['spouse_fee_total'] ?? '0.00';
        $childFeeTotal = $waiver['child_fee_total'] ?? '0.00';
        $tempFeeTotal = $waiver['temporary_fee_total'] ?? '0.00';
        $excessTotal = bcadd(bcadd($spouseFeeTotal, $childFeeTotal, 2), $tempFeeTotal, 2);
        if (bccomp($excessTotal, '0', 2) <= 0) {
            $excessTotal = $waiver['excess_fee_amount'] ?? '0.00';
        }
        $totalFee = bcadd((string) $waiverFee, $excessTotal, 2);

        if (bccomp($totalFee, '0', 2) <= 0) {
            return $this->redirect("/waivers/{$id}")->withError('لا توجد رسوم مطلوبة');
        }

        // Get member names for the receipt
        $targetMember = $db->selectOne("SELECT full_name_ar FROM members WHERE id = ?", [(int) $waiver['target_member_id']]);
        $targetName = $targetMember['full_name_ar'] ?? '';
        $sourceMember = $db->selectOne("SELECT full_name_ar FROM members WHERE id = ?", [(int) $waiver['source_member_id']]);
        $sourceName = $sourceMember['full_name_ar'] ?? '';

        // Load per-individual fees for detailed receipt
        $individualFees = WaiverProcessor::getIndividualFees((int) $id);

        // Build detailed breakdown for receipt (per-person)
        $breakdown = [
            'تنازل عن العضوية رقم: ' . ($waiver['membership_number'] ?? ''),
            'المتنازل إليه (المشتري): ' . $targetName,
            'قيمة العضوية: ' . money($waiver['membership_value_at_waiver'] ?? '0'),
            '═══════════════════════════',
            'رسوم التنازل الأساسية: ' . money($waiverFee) . ' (' . ($waiver['waiver_fee_percentage'] ?? '30') . '% من قيمة العضوية)',
        ];

        // Per-individual detailed items
        $receiptItems = [];
        $receiptItems[] = [
            'description' => 'رسوم التنازل (' . ($waiver['waiver_fee_percentage'] ?? '30') . '% من قيمة العضوية)',
            'person_name' => $targetName,
            'person_type' => 'المتنازل إليه',
            'amount' => $waiverFee,
            'calculation' => ($waiver['waiver_fee_percentage'] ?? '30') . '% × ' . money($waiver['membership_value_at_waiver'] ?? '0'),
        ];

        if (!empty($individualFees)) {
            $spouseItems = array_filter($individualFees, fn($f) => $f['person_type'] === 'spouse');
            $childItems = array_filter($individualFees, fn($f) => $f['person_type'] === 'child');
            $tempItems = array_filter($individualFees, fn($f) => $f['person_type'] === 'temporary');

            if (!empty($spouseItems)) {
                $breakdown[] = '--- رسوم الزوجات ---';
                foreach ($spouseItems as $fee) {
                    if (bccomp($fee['fee_amount'] ?? '0', '0', 2) <= 0) continue;
                    $calcMethod = ($fee['fee_type'] ?? '') === 'percentage'
                        ? $fee['fee_rate'] . '% من قيمة العضوية'
                        : money($fee['fee_rate'] ?? '0') . ' مبلغ ثابت';
                    $breakdown[] = 'الزوجة: ' . ($fee['person_name'] ?? '') . ' — ' . $calcMethod . ' = ' . money($fee['fee_amount']);
                    $receiptItems[] = [
                        'description' => 'رسوم زوجة — ' . ($fee['person_name'] ?? ''),
                        'person_name' => $fee['person_name'] ?? '',
                        'person_type' => 'زوجة',
                        'amount' => $fee['fee_amount'],
                        'calculation' => $calcMethod,
                    ];
                }
            }

            if (!empty($childItems)) {
                $breakdown[] = '--- رسوم الأبناء ---';
                foreach ($childItems as $fee) {
                    if (bccomp($fee['fee_amount'] ?? '0', '0', 2) <= 0) continue;
                    $calcMethod = ($fee['fee_type'] ?? '') === 'percentage'
                        ? $fee['fee_rate'] . '% من قيمة العضوية'
                        : money($fee['fee_rate'] ?? '0') . ' مبلغ ثابت';
                    $ageInfo = $fee['age_years'] ? ' (' . (int) $fee['age_years'] . ' سنة' . (!empty($fee['age_category']) ? ' — ' . $fee['age_category'] : '') . ')' : '';
                    $breakdown[] = 'ابن/ة: ' . ($fee['person_name'] ?? '') . $ageInfo . ' — ' . $calcMethod . ' = ' . money($fee['fee_amount']);
                    $receiptItems[] = [
                        'description' => 'رسوم ابن/ة — ' . ($fee['person_name'] ?? '') . $ageInfo,
                        'person_name' => $fee['person_name'] ?? '',
                        'person_type' => 'ابن/ة',
                        'age_years' => $fee['age_years'] ?? null,
                        'age_category' => $fee['age_category'] ?? null,
                        'amount' => $fee['fee_amount'],
                        'calculation' => $calcMethod,
                    ];
                }
            }

            if (!empty($tempItems)) {
                $breakdown[] = '--- رسوم الأعضاء المؤقتين ---';
                foreach ($tempItems as $fee) {
                    if (bccomp($fee['fee_amount'] ?? '0', '0', 2) <= 0) continue;
                    $calcMethod = ($fee['fee_type'] ?? '') === 'percentage'
                        ? $fee['fee_rate'] . '% من قيمة العضوية'
                        : money($fee['fee_rate'] ?? '0') . ' مبلغ ثابت';
                    $breakdown[] = 'عضو مؤقت: ' . ($fee['person_name'] ?? '') . ' — ' . $calcMethod . ' = ' . money($fee['fee_amount']);
                    $receiptItems[] = [
                        'description' => 'رسوم عضو مؤقت — ' . ($fee['person_name'] ?? ''),
                        'person_name' => $fee['person_name'] ?? '',
                        'person_type' => 'عضو مؤقت',
                        'amount' => $fee['fee_amount'],
                        'calculation' => $calcMethod,
                    ];
                }
            }
        } elseif (bccomp($excessTotal, '0', 2) > 0) {
            $breakdown[] = 'رسوم تابعين إضافيين: ' . money($excessTotal);
            $receiptItems[] = [
                'description' => 'رسوم تابعين إضافيين',
                'person_name' => '',
                'person_type' => 'تابعين',
                'amount' => $excessTotal,
                'calculation' => 'حسب قرار مجلس الأمناء',
            ];
        }

        $breakdown[] = '═══════════════════════════';
        $breakdown[] = 'إجمالي رسوم التنازل: ' . money($waiverFee);
        if (bccomp($spouseFeeTotal, '0', 2) > 0) $breakdown[] = 'إجمالي رسوم الزوجات: ' . money($spouseFeeTotal);
        if (bccomp($childFeeTotal, '0', 2) > 0) $breakdown[] = 'إجمالي رسوم الأبناء: ' . money($childFeeTotal);
        if (bccomp($tempFeeTotal, '0', 2) > 0) $breakdown[] = 'إجمالي رسوم المؤقتين: ' . money($tempFeeTotal);
        $breakdown[] = 'الإجمالي النهائي: ' . money($totalFee);

        // Payment request in TARGET member's name (buyer pays)
        $result = PaymentRequestService::createRequest([
            'member_id'           => (int) $waiver['target_member_id'],
            'amount'              => $totalFee,
            'payment_type'        => 'waiver_fee',
            'related_entity_type' => 'waiver_requests',
            'related_entity_id'   => (int) $id,
            'description_ar'      => 'رسوم تنازل عن عضوية #' . ($waiver['membership_number'] ?? '') . ' — ' . $targetName,
            'notes'               => json_encode([
                'fee_breakdown' => $breakdown,
                'receipt_items' => $receiptItems,
                'totals' => [
                    'waiver_fee' => $waiverFee,
                    'spouse_fee_total' => $spouseFeeTotal,
                    'child_fee_total' => $childFeeTotal,
                    'temporary_fee_total' => $tempFeeTotal,
                    'excess_total' => $excessTotal,
                    'grand_total' => $totalFee,
                ],
                'membership_number' => $waiver['membership_number'] ?? '',
                'membership_value' => $waiver['membership_value_at_waiver'] ?? '0',
                'source_member_name' => $sourceName,
                'target_member_name' => $targetName,
            ], JSON_UNESCAPED_UNICODE),
        ]);

        if (!$result['success']) {
            return $this->redirect("/waivers/{$id}")->withError('فشل إرسال طلب الدفع: ' . ($result['error'] ?? 'خطأ غير معروف'));
        }

        return $this->redirect("/waivers/{$id}")->withSuccess(
            'تم إرسال طلب الدفع إلى الخزينة باسم المتنازل إليه (' . $targetName . ') — المبلغ: ' . money($totalFee) . ' — رقم الطلب: ' . $result['request_number']
        );
    }

    public function complete(Request $request, string $id): Response
    {
        $db = App::getInstance()->db();
        $waiver = $db->selectOne("SELECT * FROM waiver_requests WHERE id = ?", [(int) $id]);
        if (!$waiver) return $this->redirect('/waivers')->withError('الطلب غير موجود');

        $targetMemberId = (int) $request->post('target_member_id', 0);
        if ($targetMemberId > 0) {
            $db->update('waiver_requests', [
                'target_member_id' => $targetMemberId,
                'updated_at'       => date('Y-m-d H:i:s'),
            ], '`id` = ?', [(int) $id]);
        } else {
            $targetMemberId = (int) ($waiver['target_member_id'] ?? 0);
        }

        if ($targetMemberId <= 0) {
            return $this->redirect("/waivers/{$id}")->withError('يجب تحديد العضو المتنازل إليه أولاً');
        }

        // BLOCKING RULE 1: Source member debts must be clear
        $sourceDebtCheck = WaiverProcessor::checkDebtsComprehensive((int) $waiver['source_member_id']);
        if (!$sourceDebtCheck['clear']) {
            return $this->redirect("/waivers/{$id}")->withError(
                'لا يمكن إتمام التنازل — مديونيات على المتنازل بمبلغ ' . money($sourceDebtCheck['total'])
            );
        }

        // BLOCKING RULE 2: Target member debts must be clear
        $targetDebtCheck = WaiverProcessor::checkDebtsComprehensive($targetMemberId);
        if (!$targetDebtCheck['clear']) {
            return $this->redirect("/waivers/{$id}")->withError(
                'لا يمكن إتمام التنازل — مديونيات على المتنازل إليه بمبلغ ' . money($targetDebtCheck['total'])
            );
        }

        // BLOCKING RULE 3: Per-category dependent check
        $originalDeps = [
            'spouses' => (int) ($waiver['original_spouses_count'] ?? 0),
            'children' => (int) ($waiver['original_children_count'] ?? 0),
            'temporary' => (int) ($waiver['original_temporary_count'] ?? 0),
            'total' => (int) ($waiver['original_dependent_count'] ?? 0),
        ];
        $targetDeps = WaiverProcessor::countDependents($targetMemberId);
        $comparison = WaiverProcessor::compareDependents($originalDeps, $targetDeps);

        if ($comparison['has_excess']) {
            $individualFees = WaiverProcessor::getIndividualFees((int) $id);
            $totalApprovedExcessFee = bcadd(
                bcadd($waiver['spouse_fee_total'] ?? '0', $waiver['child_fee_total'] ?? '0', 2),
                $waiver['temporary_fee_total'] ?? '0', 2
            );
            $legacyExcessFee = $waiver['excess_fee_amount'] ?? '0';
            $boardReviewed = !empty($individualFees) || bccomp($totalApprovedExcessFee, '0', 2) > 0 || bccomp((string) $legacyExcessFee, '0', 2) > 0;

            if (!$boardReviewed) {
                $parts = [];
                if ($comparison['excess_spouses'] > 0) $parts[] = $comparison['excess_spouses'] . ' زوجة زائدة';
                if ($comparison['excess_children'] > 0) $parts[] = $comparison['excess_children'] . ' ابن زائد';
                if ($comparison['excess_temporary'] > 0) $parts[] = $comparison['excess_temporary'] . ' مؤقت زائد';
                return $this->redirect("/waivers/{$id}")->withError(
                    'عدد التابعين يتجاوز المسموح: ' . implode(' + ', $parts) . ' — يجب اعتماد الرسوم من مجلس الأمناء'
                );
            }
        }

        // BLOCKING RULE 4: Status must be fee_paid
        if ($waiver['status'] !== 'fee_paid') {
            return $this->redirect("/waivers/{$id}")->withError('يجب سداد جميع الرسوم قبل إتمام التنازل');
        }

        // BLOCKING RULE 5: Board approval required
        if (!$waiver['approved_by']) {
            return $this->redirect("/waivers/{$id}")->withError('يجب اعتماد الطلب من مجلس الأمناء أولاً');
        }

        // Record final state
        $db->update('waiver_requests', [
            'new_dependent_count'   => $targetDeps['total'],
            'new_spouses_count'     => $targetDeps['spouses'],
            'new_children_count'    => $targetDeps['children'],
            'new_temporary_count'   => $targetDeps['temporary'],
            'annual_renewal_paid'   => 1,
            'debts_cleared'         => 1,
            'target_debts_cleared'  => 1,
            'updated_at'            => date('Y-m-d H:i:s'),
        ], '`id` = ?', [(int) $id]);

        $result = WaiverProcessor::execute((int) $id);
        if (!$result['success']) return $this->redirect("/waivers/{$id}")->withError($result['error']);

        return $this->redirect("/waivers/{$id}")->withSuccess('تم إتمام التنازل — العضوية رقم ' . ($waiver['membership_number'] ?? '') . ' نُقلت بنجاح للمتنازل إليه');
    }

    private static function getCurrentMembershipValue(\App\Core\Database $db, array $member): string
    {
        $branchId = (int) ($member['branch_id'] ?? 1);
        $qualId = !empty($member['qualification_id']) ? (int) $member['qualification_id'] : null;
        $mType = $member['membership_type'] ?? 'working';

        if ($qualId) {
            $currentPrice = $db->selectOne(
                "SELECT price FROM pricing_configs WHERE branch_id = ? AND qualification_id = ? AND membership_type = ? AND is_active = 1 AND effective_from <= CURDATE() AND (effective_to IS NULL OR effective_to >= CURDATE()) ORDER BY effective_from DESC LIMIT 1",
                [$branchId, $qualId, $mType]
            );
        } else {
            $currentPrice = $db->selectOne(
                "SELECT price FROM pricing_configs WHERE branch_id = ? AND membership_type = ? AND is_active = 1 AND effective_from <= CURDATE() AND (effective_to IS NULL OR effective_to >= CURDATE()) ORDER BY price ASC LIMIT 1",
                [$branchId, $mType]
            );
        }

        if ($currentPrice && bccomp($currentPrice['price'], '0', 2) > 0) {
            return $currentPrice['price'];
        }

        return $member['membership_value'] ?? '0.00';
    }

    private static function handleUpload(array $file, string $dir, string $prefix): ?string
    {
        $allowed = ['application/pdf', 'image/jpeg', 'image/png'];
        if (!isset($file['tmp_name']) || !is_uploaded_file($file['tmp_name'])) return null;
        if (!empty($file['type']) && !\in_array($file['type'], $allowed)) return null;
        if (($file['size'] ?? 0) > 5 * 1024 * 1024) return null;

        $ext = pathinfo($file['name'] ?? '', PATHINFO_EXTENSION) ?: 'pdf';
        $fullDir = rtrim($_SERVER['DOCUMENT_ROOT'] ?? 'public', '/') . '/' . $dir;
        if (!is_dir($fullDir)) @mkdir($fullDir, 0755, true);

        $filename = $prefix . '_' . date('Ymd_His') . '.' . $ext;
        $path = $dir . '/' . $filename;
        move_uploaded_file($file['tmp_name'], $fullDir . '/' . $filename);

        return $path;
    }
}
