<?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);
        $debtCheck = WaiverProcessor::checkDebts((int) $memberId);

        return $this->view('Waiver.Views.create', [
            'member'            => $member,
            'membership_value'  => $membershipValue,
            'waiver_pct'        => $waiverPct,
            'waiver_fee'        => $waiverFee,
            'dependents'        => $dependents,
            '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 — cannot proceed if unpaid
        $debtCheck = WaiverProcessor::checkDebts((int) $memberId);
        if (!$debtCheck['clear']) {
            return $this->redirect("/members/{$memberId}")->withError(
                'لا يمكن تقديم طلب التنازل — يوجد مديونية بمبلغ ' . money($debtCheck['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);
        $targetMemberId = (int) $request->post('target_member_id', 0);

        // 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'],
            'membership_value_at_waiver' => $membershipValue,
            'waiver_fee_percentage'      => $waiverPct,
            'waiver_fee_amount'          => $waiverFee,
            'original_dependent_count'   => $dependents['total'],
            'board_approval_required'    => 1,
            'annual_renewal_paid'        => 1,
            'debts_cleared'              => 1,
            '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]);

        if (bccomp($waiverFee, '0', 2) > 0) {
            $breakdown = [
                '📋 نوع العملية: تنازل عن العضوية',
                '💰 قيمة العضوية الحالية: ' . money($membershipValue),
                '📊 نسبة رسوم التنازل: ' . $waiverPct . '%',
                '💵 الرسوم: ' . $waiverPct . '% × ' . money($membershipValue) . ' = ' . money($waiverFee),
                '👥 عدد التابعين الأصلي: ' . $dependents['total'] . ' (زوجات: ' . $dependents['spouses'] . ' — أبناء: ' . $dependents['children'] . ' — مؤقتين: ' . $dependents['temporary'] . ')',
                '═══════════════════════════',
                '💵 الإجمالي: ' . money($waiverFee),
            ];

            $result = PaymentRequestService::createRequest([
                'member_id'           => (int) $memberId,
                'amount'              => $waiverFee,
                'payment_type'        => 'waiver_fee',
                'related_entity_type' => 'waiver_requests',
                'related_entity_id'   => (int) $waiver->id,
                'description_ar'      => 'رسوم تنازل — طلب #' . $waiver->id,
                'notes'               => json_encode(['fee_breakdown' => $breakdown], JSON_UNESCAPED_UNICODE),
            ]);

            if ($result['success']) {
                return $this->redirect("/waivers/{$waiver->id}")->withSuccess(
                    'تم تقديم طلب التنازل وإرسال طلب الدفع للخزينة — ' . money($waiverFee) . ' (' . $waiverPct . '%) — رقم الطلب: ' . $result['request_number']
                );
            }

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

        return $this->redirect("/waivers/{$waiver->id}")->withSuccess('تم تقديم طلب التنازل — الرسوم: ' . money($waiverFee) . ' (' . $waiverPct . '%)');
    }

    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('الطلب غير موجود');

        // Get live dependent counts for display
        $sourceDeps = WaiverProcessor::countDependents((int) $waiver['source_member_id']);
        $targetDeps = $waiver['target_member_id'] ? WaiverProcessor::countDependents((int) $waiver['target_member_id']) : null;

        return $this->view('Waiver.Views.show', [
            'waiver'      => $waiver,
            'source_deps' => $sourceDeps,
            'target_deps' => $targetDeps,
        ]);
    }

    public function pay(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('الطلب غير موجود');
        if (\in_array($waiver['status'], ['completed', 'fee_paid', 'rejected'])) {
            return $this->redirect("/waivers/{$id}")->withError('لا يمكن الدفع لهذا الطلب');
        }

        $amount = $waiver['waiver_fee_amount'] ?? '0.00';
        // Include excess fee if any
        $excessFee = $waiver['excess_fee_amount'] ?? '0.00';
        $totalPayment = bcadd((string) $amount, (string) $excessFee, 2);

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

        $result = PaymentService::processPayment([
            'member_id'           => (int) $waiver['source_member_id'],
            'amount'              => $totalPayment,
            'payment_type'        => 'waiver_fee',
            'payment_method'      => $request->post('payment_method', 'cash'),
            'related_entity_type' => 'waiver_requests',
            'related_entity_id'   => (int) $id,
            'description'         => 'رسوم تنازل — طلب #' . $id . (bccomp($excessFee, '0', 2) > 0 ? ' (يشمل رسوم تابعين إضافيين)' : ''),
        ]);

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

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

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

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

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

        // Handle excess dependents — board sets the percentage
        $excessPct = trim($request->post('excess_fee_percentage', ''));
        $excessFeeAmount = '0.00';
        $excessCount = 0;

        if ($waiver['target_member_id']) {
            $targetDeps = WaiverProcessor::countDependents((int) $waiver['target_member_id']);
            $originalCount = (int) $waiver['original_dependent_count'];
            if ($targetDeps['total'] > $originalCount) {
                $excessCount = $targetDeps['total'] - $originalCount;
                if ($excessPct !== '' && is_numeric($excessPct)) {
                    $membershipValue = $waiver['membership_value_at_waiver'];
                    $excessFeeAmount = bcdiv(bcmul((string) $membershipValue, $excessPct, 4), '100', 2);
                    $excessFeeAmount = bcmul($excessFeeAmount, (string) $excessCount, 2);
                }
            }
        }

        $updateData = [
            'status'                   => 'approved',
            'approved_by'              => $employee ? (int) $employee->id : null,
            'approved_at'              => date('Y-m-d H:i:s'),
            'board_decision_reference' => $boardRef ?: null,
            'updated_at'               => date('Y-m-d H:i:s'),
        ];

        if ($excessCount > 0) {
            $updateData['excess_dependent_count'] = $excessCount;
            $updateData['excess_fee_percentage'] = $excessPct !== '' ? $excessPct : null;
            $updateData['excess_fee_amount'] = $excessFeeAmount;
        }

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

        // Send payment request including excess fees if applicable
        $totalFee = bcadd((string) ($waiver['waiver_fee_amount'] ?? '0'), $excessFeeAmount, 2);
        if (bccomp($totalFee, '0', 2) > 0) {
            $breakdown = [
                '📋 نوع العملية: تنازل عن العضوية (معتمد من مجلس الأمناء)',
                '💰 رسوم التنازل: ' . money($waiver['waiver_fee_amount']),
            ];
            if (bccomp($excessFeeAmount, '0', 2) > 0) {
                $breakdown[] = '👥 رسوم أعضاء إضافيين: ' . $excessCount . ' عضو × ' . $excessPct . '% = ' . money($excessFeeAmount);
            }
            $breakdown[] = '═══════════════════════════';
            $breakdown[] = '💵 الإجمالي: ' . money($totalFee);

            PaymentRequestService::createRequest([
                'member_id'           => (int) $waiver['source_member_id'],
                'amount'              => $totalFee,
                'payment_type'        => 'waiver_fee',
                'related_entity_type' => 'waiver_requests',
                'related_entity_id'   => (int) $id,
                'description_ar'      => 'رسوم تنازل (معتمد) — طلب #' . $id,
                'notes'               => json_encode(['fee_breakdown' => $breakdown], JSON_UNESCAPED_UNICODE),
            ]);
        }

        return $this->redirect("/waivers/{$id}")->withSuccess('تمت الموافقة على طلب التنازل' . ($excessCount > 0 ? ' — تم احتساب رسوم إضافية عن ' . $excessCount . ' عضو زائد' : ''));
    }

    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('تم رفض طلب التنازل');
    }

    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('يجب تحديد العضو المتنازل إليه أولاً');
        }

        // VALIDATION 1: All financial obligations must be cleared
        $debtCheck = WaiverProcessor::checkDebts((int) $waiver['source_member_id']);
        if (!$debtCheck['clear']) {
            $debtLines = array_map(fn($d) => $d['type'] . ': ' . money($d['amount']), $debtCheck['debts']);
            return $this->redirect("/waivers/{$id}")->withError(
                'لا يمكن إتمام التنازل — توجد مديونيات مستحقة: ' . implode(' | ', $debtLines) . ' — الإجمالي: ' . money($debtCheck['total'])
            );
        }

        // VALIDATION 2: Target dependent count check
        $originalDependentCount = (int) $waiver['original_dependent_count'];
        $targetDeps = WaiverProcessor::countDependents($targetMemberId);

        if ($targetDeps['total'] > $originalDependentCount) {
            $excess = $targetDeps['total'] - $originalDependentCount;
            // If board already approved excess with fees, check that excess fee was set
            if (bccomp($waiver['excess_fee_amount'] ?? '0', '0', 2) <= 0) {
                return $this->redirect("/waivers/{$id}")->withError(
                    'عدد التابعين للعضو المتنازل إليه (' . $targetDeps['total'] . ') يتجاوز عدد التابعين الأصليين (' . $originalDependentCount . ') بمقدار ' . $excess . ' — يجب أن يحدد مجلس الأمناء نسبة الرسوم الإضافية أثناء الاعتماد'
                );
            }
        }

        // VALIDATION 3: Waiver fee must be paid
        if (!\in_array($waiver['status'], ['fee_paid', 'approved'])) {
            return $this->redirect("/waivers/{$id}")->withError('يجب سداد رسوم التنازل قبل إتمام العملية');
        }

        // Record final state
        $db->update('waiver_requests', [
            'new_dependent_count' => $targetDeps['total'],
            'annual_renewal_paid' => 1,
            '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;
    }
}
