<?php
declare(strict_types=1);

namespace App\Modules\Children\Controllers;

use App\Core\Controller;
use App\Core\Request;
use App\Core\Response;
use App\Core\App;
use App\Core\EventBus;
use App\Modules\Children\Models\Child;
use App\Modules\Children\Services\ChildFeeCalculator;
use App\Modules\Members\Services\NationalIdParser;
use App\Modules\Rules\Services\RuleEngine;
use App\Modules\Forms\Services\FormBridge;
use App\Modules\Cashier\Services\PaymentRequestService;
use App\Shared\Services\PhotoUploadService;
use App\Modules\Members\Services\MembershipRulesService;


class ChildController 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;
    }

    private static function isLocked(array $member): bool
    {
        return !empty($member['membership_number']);
    }

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

        if (!MembershipRulesService::allowsDependents($member['membership_type'] ?? 'working')) {
            return $this->redirect("/members/{$memberId}")->withError('نوع العضوية لا يسمح بإضافة تابعين');
        }

        if (self::isLocked($member) && !self::isSuperAdmin()) {
            return $this->redirect("/members/{$memberId}")->withError('لا يمكن إضافة أبناء بعد تفعيل العضوية — تواصل مع المشرف العام');
        }

        $countries = $db->select("SELECT id, nationality_ar FROM countries WHERE is_active = 1 ORDER BY nationality_ar");

        return $this->view('Children.Views.create', [
            'member'     => $member,
            'childOrder' => Child::getNextOrder((int) $memberId),
            'countries'  => $countries,
        ]);
    }

    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 (!MembershipRulesService::allowsDependents($member['membership_type'] ?? 'working')) {
            return $this->redirect("/members/{$memberId}")->withError('نوع العضوية لا يسمح بإضافة تابعين');
        }

        if (self::isLocked($member) && !self::isSuperAdmin()) {
            return $this->redirect("/members/{$memberId}")->withError('لا يمكن إضافة أبناء بعد تفعيل العضوية — تواصل مع المشرف العام');
        }

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

        $errors = [];

        if (empty(trim($data['full_name_ar'] ?? ''))) $errors[] = 'اسم الابن/الابنة مطلوب';
        if (empty($data['date_of_birth'] ?? '')) $errors[] = 'تاريخ الميلاد مطلوب';
        if (empty($data['gender'] ?? '')) $errors[] = 'النوع مطلوب';
        elseif (!in_array($data['gender'], ['male', 'female'], true)) $errors[] = 'النوع يجب أن يكون ذكر أو أنثى';
        if (empty($data['relationship'] ?? '')) $errors[] = 'نوع القرابة مطلوب';

        // Non-Egyptian: require passport instead of NID
        $isNonEgyptian = !empty($data['is_non_egyptian']);
        $passportNumber = trim($data['passport_number'] ?? '');
        if ($isNonEgyptian && $passportNumber === '') {
            $errors[] = 'رقم جواز السفر مطلوب لغير المصريين';
        }

        // Parse NID if provided (only for Egyptians)
        $nid = trim($data['national_id'] ?? '');
        if (!$isNonEgyptian && $nid !== '') {
            $parsed = NationalIdParser::parse($nid);
            if (!$parsed['is_valid']) {
                $errors = array_merge($errors, $parsed['errors']);
            } else {
                $data['date_of_birth'] = $parsed['dob'];
                $data['age_years'] = $parsed['age_years'];
                $data['age_months'] = $parsed['age_months'];
                $data['gender'] = $parsed['gender'];
            }

            // Cannot be the member themselves
            if ($nid === ($member['national_id'] ?? '')) {
                $errors[] = 'لا يمكن إضافة العضو نفسه كابن';
            }

            $dup = Child::nidExistsElsewhere($nid);
            if ($dup) {
                $errors[] = 'الرقم القومي مسجل بالفعل: ' . ($dup['data']['full_name_ar'] ?? '');
            }
        }

        // Calculate age
        if (!empty($data['date_of_birth']) && empty($data['age_years'])) {
            $age = age_from_dob($data['date_of_birth']);
            $data['age_years'] = $age['years'];
            $data['age_months'] = $age['months'];
        }

        $childAge = (int) ($data['age_years'] ?? 0);

        // NID required for Egyptian children over age threshold
        $nidRequiredAge = (int) (RuleEngine::getValue('CHILD_NID_REQUIRED_AGE', 'value') ?? 16);
        if (!$isNonEgyptian && $childAge >= $nidRequiredAge && $nid === '') {
            $errors[] = 'الأبناء فوق ' . $nidRequiredAge . ' سنة يجب أن يكون لديهم رقم قومي';
        }

        $minAgeGap = (int) (RuleEngine::getValue('CHILD_MIN_AGE_GAP', 'value') ?? 15);
        $maxAgeGap = (int) (RuleEngine::getValue('CHILD_MAX_AGE_GAP', 'value') ?? 60);
        if (!empty($data['date_of_birth']) && !empty($member['date_of_birth'])) {
            $memberAge = age_from_dob($member['date_of_birth']);
            $ageGap = $memberAge['years'] - $childAge;
            if ($ageGap < $minAgeGap) {
                $errors[] = 'الحد الأدنى لفرق السن بين العضو والابن ' . $minAgeGap . ' سنة';
            }
            if ($ageGap > $maxAgeGap) {
                $errors[] = 'الحد الأقصى لفرق السن بين العضو والابن ' . $maxAgeGap . ' سنة';
            }
        }

        $stepchildMaxAge = (int) (RuleEngine::getValue('STEPCHILD_MAX_AGE', 'value') ?? 25);
        $childMaxAge = (int) (RuleEngine::getValue('CHILD_MAX_AGE', 'value') ?? RuleEngine::getValue('CHILD_AUTO_DELETE_AGE', 'value') ?? 25);
        if (($data['relationship'] ?? '') === 'stepchild' && $childAge >= $stepchildMaxAge) {
            $errors[] = 'أبناء الزوج/الزوجة لا يمكن أن يتجاوز عمرهم ' . $stepchildMaxAge . ' سنة';
        }

        if ($childAge >= $childMaxAge && ($data['relationship'] ?? '') !== 'stepchild') {
            $errors[] = 'لا يمكن إضافة أبناء فوق ' . $childMaxAge . ' سنة';
        }

        $photoFile = $_FILES['photo'] ?? [];
        if (!PhotoUploadService::isUploaded($photoFile)) {
            $errors[] = 'الصورة الشخصية مطلوبة';
        } else {
            $photoValidation = PhotoUploadService::validate($photoFile);
            if (!$photoValidation['valid']) {
                $errors = array_merge($errors, $photoValidation['errors']);
            }
        }

        if (!empty($errors)) {
            $session = App::getInstance()->session();
            $session->flash('_alerts', array_map(fn($e) => ['type' => 'error', 'message' => $e], $errors));
            $session->flash('_old_input', $data);
            return $this->redirect("/members/{$memberId}/children/create");
        }

        // Calculate fee
        $feeCalc = ChildFeeCalculator::calculate((int) $memberId, $data);

        if (($feeCalc['classification'] ?? '') === 'not_accepted') {
            return $this->redirect("/members/{$memberId}/children/create")
                ->withError($feeCalc['error'] ?? 'لا يمكن إضافة هذا الابن');
        }

        $childOrder = $feeCalc['child_order'] ?? Child::getNextOrder((int) $memberId);
        $classification = $feeCalc['classification'] ?? 'included';

        $totalFee = $feeCalc['total_fee'] ?? $feeCalc['fee'] ?? '0.00';
        $hasFee = bccomp($totalFee, '0', 2) > 0;

        $breakdownJson = !empty($feeCalc['breakdown']) ? json_encode($feeCalc['breakdown'], JSON_UNESCAPED_UNICODE) : null;

        $child = Child::create([
            'member_id'                => (int) $memberId,
            'child_order'              => $childOrder,
            'full_name_ar'             => trim($data['full_name_ar']),
            'full_name_en'             => trim($data['full_name_en'] ?? ''),
            'national_id'              => $nid ?: null,
            'passport_number'          => $isNonEgyptian ? $passportNumber : null,
            'birth_certificate_number' => $data['birth_certificate_number'] ?? null,
            'date_of_birth'            => $data['date_of_birth'],
            'age_years'                => (int) ($data['age_years'] ?? 0),
            'age_months'               => (int) ($data['age_months'] ?? 0),
            'gender'                   => $data['gender'],
            'relationship'             => $data['relationship'],
            'school_faculty'           => $data['school_faculty'] ?? null,
            'nationality'              => $data['nationality'] ?? 'مصري',
            'classification'           => $classification,
            'addition_fee'             => $totalFee,
            'fee_breakdown_json'       => $breakdownJson,
            'status'                   => $hasFee ? 'pending_payment' : 'active',
            'remarks'                  => $data['remarks'] ?? null,
        ]);

        $photoResult = PhotoUploadService::upload($photoFile, 'children', (int) $child->id);
        if ($photoResult) {
            $child->update(['photo_path' => $photoResult['path']]);
        }

        if (FormBridge::exists('ADDITION_CHILD')) {
            FormBridge::submit('ADDITION_CHILD', $data, (int) $memberId, 'إضافة ابن: ' . trim($data['full_name_ar']));
        }

        EventBus::dispatch('child.added', [
            'member_id'      => (int) $memberId,
            'child_id'       => (int) $child->id,
            'classification' => $classification,
            'fee'            => $totalFee,
        ]);

        if ($hasFee && !empty($member['membership_number'])) {
            $breakdown = $feeCalc['breakdown'] ?? [];
            $childLabel = ($data['gender'] ?? '') === 'male' ? 'ابن' : 'ابنة';
            PaymentRequestService::createRequest([
                'member_id'           => (int) $memberId,
                'amount'              => $totalFee,
                'payment_type'        => 'addition_fee',
                'related_entity_type' => 'children',
                'related_entity_id'   => (int) $child->id,
                'description_ar'      => 'رسوم إضافة ' . $childLabel . ' — ' . trim($data['full_name_ar']),
                'notes'               => json_encode(['fee_breakdown' => $breakdown], JSON_UNESCAPED_UNICODE),
            ]);
            return $this->redirect("/members/{$memberId}")
                ->withSuccess('تم إضافة الابن/الابنة — التصنيف: ' . $child->getClassificationLabel() . ' — الرسوم: ' . money($totalFee) . ' — تم إرسالها للخزينة تلقائياً');
        }

        if ($hasFee) {
            return $this->redirect("/members/{$memberId}")
                ->withSuccess('تم إضافة الابن/الابنة — التصنيف: ' . $child->getClassificationLabel() . ' — الرسوم: ' . money($totalFee) . ' — سيتم تحصيلها ضمن الفاتورة المجمعة');
        }

        return $this->redirect("/members/{$memberId}")
            ->withSuccess('تم إضافة الابن/الابنة — التصنيف: ' . $child->getClassificationLabel() . ' — مشمول بدون رسوم');
    }

    public function show(Request $request, string $memberId, string $id): Response
    {
        $child = Child::find((int) $id);
        if (!$child || (int) $child->member_id !== (int) $memberId) {
            return $this->redirect("/members/{$memberId}")->withError('بيانات الابن غير موجودة');
        }

        $db = App::getInstance()->db();
        $member = $db->selectOne("SELECT * FROM members WHERE id = ?", [(int) $memberId]);

        return $this->view('Children.Views.show', ['member' => $member, 'child' => $child]);
    }

    public function edit(Request $request, string $memberId, string $id): Response
    {
        $child = Child::find((int) $id);
        if (!$child || (int) $child->member_id !== (int) $memberId) {
            return $this->redirect("/members/{$memberId}")->withError('بيانات الابن غير موجودة');
        }

        $db = App::getInstance()->db();
        $member = $db->selectOne("SELECT * FROM members WHERE id = ?", [(int) $memberId]);

        if (self::isLocked($member) && !self::isSuperAdmin()) {
            return $this->redirect("/members/{$memberId}")->withError('لا يمكن تعديل البيانات بعد تفعيل العضوية — تواصل مع المشرف العام');
        }

        return $this->view('Children.Views.edit', ['member' => $member, 'child' => $child]);
    }

    public function update(Request $request, string $memberId, string $id): Response
    {
        $child = Child::find((int) $id);
        if (!$child || (int) $child->member_id !== (int) $memberId) {
            return $this->redirect("/members/{$memberId}")->withError('بيانات الابن غير موجودة');
        }

        $db = App::getInstance()->db();
        $member = $db->selectOne("SELECT * FROM members WHERE id = ?", [(int) $memberId]);
        if (self::isLocked($member) && !self::isSuperAdmin()) {
            return $this->redirect("/members/{$memberId}")->withError('لا يمكن تعديل البيانات بعد تفعيل العضوية — تواصل مع المشرف العام');
        }

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

        $updateData = [];
        foreach (['full_name_en', 'school_faculty', 'remarks'] as $field) {
            if (array_key_exists($field, $data)) {
                $val = $data[$field];
                $updateData[$field] = ($val === '' || $val === null) ? null : $val;
            }
        }

        if (!empty($_FILES['photo']) && PhotoUploadService::isUploaded($_FILES['photo'])) {
            $photoValidation = PhotoUploadService::validate($_FILES['photo']);
            if ($photoValidation['valid']) {
                $photoResult = PhotoUploadService::upload($_FILES['photo'], 'children', (int) $id);
                if ($photoResult) {
                    $updateData['photo_path'] = $photoResult['path'];
                }
            }
        }

        if (!empty($updateData)) {
            $child->update($updateData);
        }

        return $this->redirect("/members/{$memberId}")->withSuccess('تم تحديث بيانات الابن/الابنة');
    }

    public function archive(Request $request, string $memberId, string $id): Response
    {
        $child = Child::find((int) $id);
        if (!$child || (int) $child->member_id !== (int) $memberId) {
            return $this->redirect("/members/{$memberId}")->withError('بيانات الابن غير موجودة');
        }

        $db = App::getInstance()->db();
        $member = $db->selectOne("SELECT * FROM members WHERE id = ?", [(int) $memberId]);
        if (self::isLocked($member) && !self::isSuperAdmin()) {
            return $this->redirect("/members/{$memberId}")->withError('لا يمكن إزالة التابعين بعد تفعيل العضوية — تواصل مع المشرف العام');
        }

        $reason = trim((string) $request->post('reason', ''));
        if ($reason === '') {
            return $this->redirect("/members/{$memberId}")->withError('يجب إدخال سبب الإزالة');
        }

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

        $db->update('children', [
            'is_archived' => 1,
            'archived_at' => date('Y-m-d H:i:s'),
            'archived_by' => $employee ? (int) $employee->id : null,
            'status'      => 'inactive',
            'updated_at'  => date('Y-m-d H:i:s'),
        ], '`id` = ?', [(int) $id]);

        EventBus::dispatch('child.removed', [
            'member_id' => (int) $memberId,
            'child_id'  => (int) $id,
            'reason'    => $reason,
        ]);

        return $this->redirect("/members/{$memberId}")->withSuccess('تم إزالة الابن/الابنة');
    }

    public function freeze(Request $request, string $memberId, string $id): Response
    {
        $child = Child::find((int) $id);
        if (!$child || (int) $child->member_id !== (int) $memberId) {
            return $this->redirect("/members/{$memberId}")->withError('بيانات الابن غير موجودة');
        }

        $reason = trim((string) $request->post('freeze_reason', 'بلوغ سن 25'));
        $db = App::getInstance()->db();

        $db->update('children', [
            'is_frozen'      => 1,
            'frozen_at'      => date('Y-m-d H:i:s'),
            'frozen_reason'  => $reason,
            'classification' => 'frozen',
            'status'         => 'frozen',
            'updated_at'     => date('Y-m-d H:i:s'),
        ], '`id` = ?', [(int) $id]);

        EventBus::dispatch('child.frozen', [
            'member_id' => (int) $memberId,
            'child_id'  => (int) $id,
            'reason'    => $reason,
        ]);

        return $this->redirect("/members/{$memberId}")->withSuccess('تم تجميد عضوية الابن/الابنة');
    }

    public function calculateFee(Request $request): Response
    {
        $memberId = (int) $request->post('member_id', 0);
        if ($memberId <= 0) {
            return $this->json(['error' => 'بيانات غير صالحة'], 422);
        }

        $result = ChildFeeCalculator::calculate($memberId, $request->all());
        return $this->json($result);
    }
}