<?php
declare(strict_types=1);

namespace App\Modules\Members\Controllers;

use App\Core\Controller;
use App\Core\Request;
use App\Core\Response;
use App\Core\App;
use App\Core\EventBus;
use App\Modules\Members\Models\Member;
use App\Modules\Members\Services\NationalIdParser;
use App\Modules\Members\Services\MemberNumberGenerator;
use App\Modules\Members\Services\MemberSearchService;
use App\Modules\Members\Services\BillingService;
use App\Modules\Payments\Services\PaymentService;
use App\Modules\Rules\Services\RuleEngine;
use App\Modules\Pricing\Models\SpecialDiscount;

class MemberController extends Controller
{
    private static function isSuperAdmin(): bool
    {
        $employee = App::getInstance()->currentEmployee();
        if (!$employee) return false;
        $db = App::getInstance()->db();
        $row = $db->selectOne(
            "SELECT 1 FROM employee_roles er JOIN roles r ON r.id = er.role_id WHERE er.employee_id = ? AND r.role_code = 'super_admin' AND er.is_active = 1 LIMIT 1",
            [(int) $employee->id]
        );
        return $row !== null;
    }

    public function index(Request $request): Response
    {
        $db = App::getInstance()->db();
        $filters = [
            'q' => trim((string) $request->get('q', '')),
            'status' => $request->get('status', ''),
            'branch_id' => $request->get('branch_id', ''),
            'date_from' => $request->get('date_from', ''),
            'date_to' => $request->get('date_to', ''),
        ];
        $page = max(1, (int) $request->get('page', 1));
        $perPage = 25;
        $where = 'm.is_archived = 0';
        $params = [];
        if ($filters['q'] !== '') { $where .= ' AND (m.full_name_ar LIKE ? OR m.national_id LIKE ? OR m.membership_number LIKE ? OR m.phone_mobile LIKE ? OR m.form_number LIKE ?)'; $s = '%' . $filters['q'] . '%'; $params = array_merge($params, [$s, $s, $s, $s, $s]); }
        if ($filters['status'] !== '') { $where .= ' AND m.status = ?'; $params[] = $filters['status']; }
        if ($filters['branch_id'] !== '') { $where .= ' AND m.branch_id = ?'; $params[] = (int) $filters['branch_id']; }
        if ($filters['date_from'] !== '') { $where .= ' AND m.created_at >= ?'; $params[] = $filters['date_from'] . ' 00:00:00'; }
        if ($filters['date_to'] !== '') { $where .= ' AND m.created_at <= ?'; $params[] = $filters['date_to'] . ' 23:59:59'; }
        $countRow = $db->selectOne("SELECT COUNT(*) as cnt FROM members m WHERE {$where}", $params);
        $total = (int) ($countRow['cnt'] ?? 0);
        $offset = ($page - 1) * $perPage;
        $members = $db->select("SELECT m.*, b.name_ar as branch_name FROM members m LEFT JOIN branches b ON b.id = m.branch_id WHERE {$where} ORDER BY m.id DESC LIMIT {$perPage} OFFSET {$offset}", $params);
        $pagination = \App\Core\Pagination::paginate($total, $perPage, $page);
        $branches = $db->select("SELECT id, name_ar FROM branches WHERE is_active = 1 ORDER BY name_ar");
        return $this->view('Members.Views.index', ['members' => $members, 'branches' => $branches, 'statuses' => Member::getStatusOptions(), 'filters' => $filters, 'pagination' => $pagination]);
    }

    public function create(Request $request): Response
    {
        $db = App::getInstance()->db();
        $branches = $db->select("SELECT id, name_ar FROM branches WHERE is_active = 1 ORDER BY name_ar");
        return $this->view('Members.Views.create', [
            'branches' => $branches,
            'nextFormNumber' => MemberNumberGenerator::next(),
            'formFee' => MemberNumberGenerator::getFormFee(),
            'needsStartNumber' => (MemberNumberGenerator::next() === null),
        ]);
    }

    public function store(Request $request): Response
    {
        $db = App::getInstance()->db();
        $startNumber = $request->post('form_start_number');
        if ($startNumber !== null && $startNumber !== '') { MemberNumberGenerator::setStartNumber((int) $startNumber); }

        $fullNameAr = trim((string) $request->post('full_name_ar', ''));
        $nationalId = trim((string) $request->post('national_id', ''));
        $phoneMobile = trim((string) $request->post('phone_mobile', ''));
        $branchId = (int) $request->post('branch_id', 0);
        $errors = [];
        if ($fullNameAr === '' || mb_strlen($fullNameAr) < 5) $errors[] = 'الاسم بالعربي مطلوب (5 أحرف على الأقل)';
        if ($phoneMobile === '' || !preg_match('/^01[0125]\d{8}$/', $phoneMobile)) $errors[] = 'رقم المحمول غير صالح';
        if ($branchId <= 0) $errors[] = 'الفرع مطلوب';

        $dob = $gender = $govCode = null; $ageYears = $ageMonths = null; $idType = 'national_id';
        if ($nationalId !== '') {
            $parsed = NationalIdParser::parse($nationalId);
            if (!$parsed['is_valid']) { $errors = array_merge($errors, $parsed['errors']); }
            else { $dob = $parsed['dob']; $ageYears = $parsed['age_years']; $ageMonths = $parsed['age_months']; $gender = $parsed['gender']; $govCode = $parsed['governorate_code']; }
            $dup = $db->selectOne("SELECT id, full_name_ar FROM members WHERE national_id = ? AND is_archived = 0", [$nationalId]);
            if ($dup) $errors[] = 'الرقم القومي مسجل بالفعل: ' . $dup['full_name_ar'];
        } else {
            $dob = $request->post('date_of_birth', ''); $gender = $request->post('gender', '');
            if (!$dob) $errors[] = 'تاريخ الميلاد مطلوب'; if (!$gender) $errors[] = 'النوع مطلوب';
            if ($dob) { $age = age_from_dob($dob); $ageYears = $age['years']; $ageMonths = $age['months']; }
            $idType = 'passport';
        }
        if (!empty($errors)) { $session = App::getInstance()->session(); $session->flash('_alerts', array_map(fn($e) => ['type' => 'error', 'message' => $e], $errors)); $session->flash('_old_input', $request->all()); return $this->redirect('/members/create'); }

        $formNumber = MemberNumberGenerator::next();
        if (!$formNumber) return $this->redirect('/members/create')->withError('يجب تحديد رقم بداية الاستمارات');

        $member = Member::create(['full_name_ar' => $fullNameAr, 'national_id' => $nationalId ?: null, 'passport_number' => $request->post('passport_number') ?: null, 'id_type' => $idType, 'date_of_birth' => $dob, 'age_years' => $ageYears, 'age_months' => $ageMonths, 'gender' => $gender, 'governorate_code' => $govCode, 'phone_mobile' => $phoneMobile, 'branch_id' => $branchId, 'nationality' => 'مصري', 'form_number' => (string) $formNumber, 'form_date' => date('Y-m-d'), 'status' => 'potential', 'membership_type' => 'working', 'member_category' => 'working_member']);
        EventBus::dispatch('member.created', ['member_id' => (int) $member->id, 'form_number' => (string) $formNumber]);
        return $this->redirect('/members/' . $member->id)->withSuccess('تم تسجيل العضو — استمارة رقم: ' . $formNumber);
    }

    public function show(Request $request, string $id): Response
    {
        $db = App::getInstance()->db();
        $member = Member::find((int) $id);
        if (!$member || $member->is_archived) return $this->redirect('/members')->withError('العضو غير موجود');

        $branch = $db->selectOne("SELECT name_ar FROM branches WHERE id = ?", [(int) $member->branch_id]);
        $qualification = $member->qualification_id ? $db->selectOne("SELECT name_ar FROM qualifications WHERE id = ?", [(int) $member->qualification_id]) : null;

        $spouses = []; $children = [];
        try { $spouses = $db->select("SELECT * FROM spouses WHERE member_id = ? AND is_archived = 0 ORDER BY spouse_order", [(int) $id]); } catch (\Throwable $e) {}
        try { $children = $db->select("SELECT * FROM children WHERE member_id = ? AND is_archived = 0 ORDER BY child_order", [(int) $id]); } catch (\Throwable $e) {}

        $bill = BillingService::getMemberBill((int) $id);
        $formFilled = ($member->qualification_id !== null && $member->qualification_id > 0);

        $specialDiscount = null;
        if ($member->special_discount_id) {
            $specialDiscount = $db->selectOne("SELECT * FROM special_discounts WHERE id = ?", [(int) $member->special_discount_id]);
        }

        return $this->view('Members.Views.show', [
            'member' => $member,
            'branchName' => $branch['name_ar'] ?? '—',
            'qualificationName' => $qualification['name_ar'] ?? '—',
            'spouses' => $spouses,
            'children' => $children,
            'bill' => $bill,
            'formFee' => MemberNumberGenerator::getFormFee(),
            'formFilled' => $formFilled,
            'specialDiscount' => $specialDiscount,
        ]);
    }

    public function payFormFee(Request $request, string $id): Response
    {
        $member = Member::find((int) $id);
        if (!$member) return $this->redirect('/members')->withError('العضو غير موجود');

        $result = PaymentService::processPayment([
            'member_id' => (int) $id, 'amount' => MemberNumberGenerator::getFormFee(),
            'payment_type' => 'form_fee', 'payment_method' => $request->post('payment_method', 'cash'),
            'related_entity_type' => 'members', 'related_entity_id' => (int) $id,
            'description' => 'رسوم استمارة عضوية رقم ' . ($member->form_number ?? ''),
        ]);
        if (!$result['success']) return $this->redirect('/members/' . $id)->withError($result['error']);
        return $this->redirect('/members/' . $id)->withSuccess('تم دفع رسوم الاستمارة — إيصال: ' . $result['receipt_number']);
    }

    public function payMembership(Request $request, string $id): Response
    {
        $db = App::getInstance()->db();
        $member = Member::find((int) $id);
        if (!$member) return $this->redirect('/members')->withError('العضو غير موجود');

        $paymentType = trim((string) $request->post('payment_type', ''));
        $amount = trim((string) $request->post('amount', '0'));
        $paymentMethod = trim((string) $request->post('payment_method', 'cash'));

        if (bccomp($amount, '0.01', 2) < 0) return $this->redirect('/members/' . $id)->withError('المبلغ غير صالح');

        $result = PaymentService::processPayment([
            'member_id' => (int) $id, 'amount' => $amount,
            'payment_type' => $paymentType, 'payment_method' => $paymentMethod,
            'related_entity_type' => 'members', 'related_entity_id' => (int) $id,
            'description' => ($paymentType === 'down_payment' ? 'مقدم تقسيط' : 'قيمة العضوية') . ' — استمارة ' . ($member->form_number ?? ''),
        ]);
        if (!$result['success']) return $this->redirect('/members/' . $id)->withError($result['error']);

        $membershipNumber = MemberNumberGenerator::assign((int) $id);
        $member->update(['status' => 'active']);

        if ($paymentType === 'down_payment') {
            $membershipValue = $member->membership_value ?? '0.00';
            $remaining = bcsub($membershipValue, $amount, 2);
            if (bccomp($remaining, '0', 2) > 0) {
                $months = min(30, max(1, (int) $request->post('installment_months', 30)));
                $interestRateData = RuleEngine::get('INSTALLMENT_INTEREST_RATE');
                $interestRate = $interestRateData['percentage'] ?? '22.00';
                $totalInterest = bcdiv(bcmul($remaining, $interestRate, 4), '100', 2);
                $totalWithInterest = bcadd($remaining, $totalInterest, 2);
                $monthlyPayment = bcdiv($totalWithInterest, (string) $months, 2);

                $planId = $db->insert('installment_plans', [
                    'member_id' => (int) $id, 'related_entity_type' => 'members', 'related_entity_id' => (int) $id,
                    'total_amount' => $membershipValue, 'down_payment' => $amount,
                    'remaining_balance' => $remaining, 'interest_rate' => $interestRate,
                    'total_interest' => $totalInterest, 'total_with_interest' => $totalWithInterest,
                    'number_of_months' => $months, 'monthly_payment' => $monthlyPayment,
                    'start_date' => date('Y-m-d'), 'status' => 'active',
                    'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s'),
                ]);

                $rem = $totalWithInterest;
                for ($i = 1; $i <= $months; $i++) {
                    $principal = bcdiv($remaining, (string) $months, 2);
                    $interest = bcdiv($totalInterest, (string) $months, 2);
                    $instAmount = bcadd($principal, $interest, 2);
                    $rem = bcsub($rem, $instAmount, 2);
                    if (bccomp($rem, '0', 2) < 0) $rem = '0.00';
                    $db->insert('installment_schedule', [
                        'installment_plan_id' => $planId, 'installment_number' => $i,
                        'due_date' => date('Y-m-d', strtotime("+{$i} months")),
                        'amount' => $instAmount, 'principal' => $principal, 'interest' => $interest,
                        'remaining_after' => $rem, 'paid_amount' => '0.00', 'status' => 'pending',
                        'created_at' => date('Y-m-d H:i:s'), 'updated_at' => date('Y-m-d H:i:s'),
                    ]);
                }

                EventBus::dispatch('installment.plan_created', [
                    'plan_id'      => $planId,
                    'member_id'    => (int) $id,
                    'total_amount' => $totalWithInterest,
                ]);
            }
        }

        EventBus::dispatch('member.activated', ['member_id' => (int) $id, 'membership_number' => $membershipNumber]);

        $msg = '✅ تم السداد — رقم العضوية: ' . $membershipNumber . ' — إيصال: ' . $result['receipt_number'];
        if ($paymentType === 'down_payment') $msg .= ' — تم إنشاء خطة تقسيط';
        return $this->redirect('/members/' . $id)->withSuccess($msg);
    }

    public function fillForm(Request $request, string $id): Response
    {
        $db = App::getInstance()->db();
        $member = Member::find((int) $id);
        if (!$member) return $this->redirect('/members')->withError('العضو غير موجود');
        $formFeePaid = $db->selectOne("SELECT id FROM payments WHERE member_id = ? AND payment_type = 'form_fee' AND is_voided = 0 LIMIT 1", [(int) $id]);
        if (!$formFeePaid) return $this->redirect('/members/' . $id)->withError('⚠ يجب دفع رسوم الاستمارة أولاً');
        return $this->view('Members.Views.fill-form', [
            'member' => $member,
            'branches' => $db->select("SELECT id, name_ar FROM branches WHERE is_active = 1 ORDER BY name_ar"),
            '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"),
            'specialDiscounts' => SpecialDiscount::allActive(),
        ]);
    }

    public function saveFillForm(Request $request, string $id): Response
    {
        $db = App::getInstance()->db();
        $member = Member::find((int) $id);
        if (!$member) return $this->redirect('/members')->withError('العضو غير موجود');
        $formFeePaid = $db->selectOne("SELECT id FROM payments WHERE member_id = ? AND payment_type = 'form_fee' AND is_voided = 0 LIMIT 1", [(int) $id]);
        if (!$formFeePaid) return $this->redirect('/members/' . $id)->withError('⚠ يجب دفع رسوم الاستمارة أولاً');

        $data = $request->all(); unset($data['_csrf_token']);
        $fields = ['full_name_en','place_of_birth','nationality','religion','qualification_id','marital_status','id_issue_date','id_expiry_date','phone_home','phone_international','email','emergency_name','emergency_phone','residence_type','residence_address','landmark','floor','apartment','area','governorate','correspondence_address','employment_type','occupation','job_title','employment_date','business_address','office_phone','office_fax','business_activity','referral_source'];
        $update = [];
        foreach ($fields as $f) { if (array_key_exists($f, $data)) { $v = trim((string) ($data[$f] ?? '')); $update[$f] = $v === '' ? null : $v; } }
        if (isset($update['qualification_id'])) $update['qualification_id'] = $update['qualification_id'] ? (int) $update['qualification_id'] : null;

        if (!empty($update['qualification_id'])) {
            $pricing = $db->selectOne("SELECT price FROM pricing_configs WHERE branch_id = ? AND qualification_id = ? AND membership_type = 'working' AND is_active = 1 AND effective_from <= CURDATE() AND (effective_to IS NULL OR effective_to >= CURDATE()) ORDER BY effective_from DESC LIMIT 1", [(int) $member->branch_id, (int) $update['qualification_id']]);
            if ($pricing) $update['membership_value'] = $pricing['price'];
        }

        // Special discount
        $discountId = trim((string) ($data['special_discount_id'] ?? ''));
        if ($discountId !== '' && $discountId !== '0') {
            $discountRow = $db->selectOne("SELECT * FROM special_discounts WHERE id = ? AND is_active = 1", [(int) $discountId]);
            if ($discountRow) {
                $update['special_discount_id'] = (int) $discountId;
                $mValue = $update['membership_value'] ?? ($member->membership_value ?? '0.00');
                $update['discount_amount'] = bcdiv(bcmul($mValue, $discountRow['discount_percentage'], 4), '100', 2);
            }
        }

        if ($member->status === 'potential') $update['status'] = 'under_review';
        if (!empty($update)) $member->update($update);
        return $this->redirect('/members/' . $id)->withSuccess('تم ملء الاستمارة');
    }

    public function edit(Request $request, string $id): Response
    {
        $db = App::getInstance()->db();
        $member = Member::find((int) $id);
        if (!$member) return $this->redirect('/members')->withError('العضو غير موجود');
        return $this->view('Members.Views.edit', [
            'member'           => $member,
            'branches'         => $db->select("SELECT id, name_ar FROM branches WHERE is_active = 1"),
            '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"),
            'countries'        => $db->select("SELECT nationality_ar FROM countries WHERE is_active = 1 ORDER BY name_ar"),
            'isSuperAdmin'     => self::isSuperAdmin(),
            'specialDiscounts' => SpecialDiscount::allActive(),
        ]);
    }

    public function update(Request $request, string $id): Response
    {
        $db = App::getInstance()->db();
        $member = Member::find((int) $id);
        if (!$member) return $this->redirect('/members')->withError('العضو غير موجود');

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

        $isSuperAdmin = self::isSuperAdmin();

        $allowed = ['full_name_en','phone_home','phone_mobile','phone_international','email','emergency_name','emergency_phone','residence_type','residence_address','landmark','floor','apartment','area','governorate','correspondence_address','employment_type','occupation','job_title','employment_date','business_address','office_phone','office_fax','business_activity','referral_source','religion','marital_status'];

        $update = [];
        foreach ($allowed as $f) {
            if (array_key_exists($f, $data)) {
                $v = trim((string) ($data[$f] ?? ''));
                $update[$f] = $v === '' ? null : $v;
            }
        }

        // ── SuperAdmin-only fields: full_name_ar, national_id ──
        if ($isSuperAdmin) {
            $errors = [];

            // Name change
            if (array_key_exists('full_name_ar', $data)) {
                $newName = trim((string) $data['full_name_ar']);
                if ($newName !== '' && mb_strlen($newName) >= 5) {
                    $update['full_name_ar'] = $newName;
                } elseif ($newName !== '') {
                    $errors[] = 'الاسم بالعربي يجب أن يكون 5 أحرف على الأقل';
                }
            }

            // National ID change
            if (array_key_exists('national_id', $data)) {
                $newNid = trim((string) $data['national_id']);

                if ($newNid === '') {
                    // Allow clearing NID (e.g., for passport-based members)
                    $update['national_id'] = null;
                } elseif ($newNid !== ($member->national_id ?? '')) {
                    // Validate new NID
                    $parsed = NationalIdParser::parse($newNid);
                    if (!$parsed['is_valid']) {
                        $errors = array_merge($errors, $parsed['errors']);
                    } else {
                        // Check duplicate
                        $dup = $db->selectOne(
                            "SELECT id, full_name_ar FROM members WHERE national_id = ? AND is_archived = 0 AND id != ?",
                            [$newNid, (int) $id]
                        );
                        if ($dup) {
                            $errors[] = 'الرقم القومي مسجل بالفعل للعضو: ' . $dup['full_name_ar'];
                        } else {
                            $update['national_id'] = $newNid;
                            $update['date_of_birth'] = $parsed['dob'];
                            $update['age_years'] = $parsed['age_years'];
                            $update['age_months'] = $parsed['age_months'];
                            $update['gender'] = $parsed['gender'];
                            $update['governorate_code'] = $parsed['governorate_code'];
                        }
                    }
                }
            }

            if (!empty($errors)) {
                $session = App::getInstance()->session();
                $session->flash('_alerts', array_map(fn($e) => ['type' => 'error', 'message' => $e], $errors));
                return $this->redirect('/members/' . $id . '/edit');
            }
        }

        // ── Special Discount handling ──
        if (array_key_exists('special_discount_id', $data)) {
            $discountId = trim((string) ($data['special_discount_id'] ?? ''));
            if ($discountId === '' || $discountId === '0') {
                $update['special_discount_id'] = null;
                $update['discount_amount'] = null;
            } else {
                $discountRow = $db->selectOne("SELECT * FROM special_discounts WHERE id = ? AND is_active = 1", [(int) $discountId]);
                if ($discountRow) {
                    $update['special_discount_id'] = (int) $discountId;
                    $membershipValue = $member->membership_value ?? '0.00';
                    $update['discount_amount'] = bcdiv(bcmul($membershipValue, $discountRow['discount_percentage'], 4), '100', 2);

                    // Handle document upload if required
                    if ($discountRow['requires_document'] && !empty($_FILES['discount_document']['tmp_name'])) {
                        $file = $_FILES['discount_document'];
                        $allowedTypes = ['application/pdf', 'image/jpeg', 'image/png'];
                        $finfo = new \finfo(FILEINFO_MIME_TYPE);
                        $mimeType = $finfo->file($file['tmp_name']);
                        if (in_array($mimeType, $allowedTypes) && $file['size'] <= 10485760) {
                            $ext = pathinfo($file['name'], PATHINFO_EXTENSION);
                            $storedName = 'discount_' . (int) $id . '_' . date('Ymd_His') . '_' . bin2hex(random_bytes(4)) . '.' . $ext;
                            $uploadDir = App::getInstance()->basePath() . '/storage/uploads/discounts/';
                            if (!is_dir($uploadDir)) mkdir($uploadDir, 0755, true);
                            if (move_uploaded_file($file['tmp_name'], $uploadDir . $storedName)) {
                                $update['special_discount_document'] = 'storage/uploads/discounts/' . $storedName;
                            }
                        }
                    }
                }
            }
        }

        if (!empty($update)) $member->update($update);
        return $this->redirect('/members/' . $id)->withSuccess('تم تحديث البيانات');
    }

    public function changeStatus(Request $request, string $id): Response
    {
        $member = Member::find((int) $id);
        if (!$member) return $this->redirect('/members')->withError('العضو غير موجود');
        $newStatus = trim((string) $request->post('status', ''));
        if (!in_array($newStatus, array_keys(Member::getStatusOptions()))) return $this->redirect('/members/' . $id)->withError('حالة غير صالحة');
        $old = $member->status; $member->update(['status' => $newStatus]);
        EventBus::dispatch('member.status_changed', ['member_id' => (int) $id, 'old' => $old, 'new' => $newStatus]);
        return $this->redirect('/members/' . $id)->withSuccess('تم تغيير الحالة');
    }

    public function search(Request $request): Response
    {
        $q = trim((string) $request->get('q', ''));
        return $this->view('Members.Views.search', ['query' => $q, 'results' => ($q !== '' && mb_strlen($q) >= 2) ? MemberSearchService::search($q, 50) : []]);
    }
}