<?php
declare(strict_types=1);

namespace App\Modules\SportsActivity\Services;

use App\Core\App;
use App\Core\EventBus;
use App\Modules\Cashier\Services\PaymentRequestService;
use App\Modules\Carnets\Services\QRCodeGenerator;
use App\Modules\Members\Services\NationalIdParser;
use App\Shared\Services\PhotoUploadService;

final class RegistrationWizardService
{
    public static function startRegistration(array $playerData): array
    {
        $db = App::getInstance()->db();
        $employee = App::getInstance()->currentEmployee();
        $branch = App::getInstance()->currentBranch();

        $nationalId = trim($playerData['national_id'] ?? '');
        $playerType = $playerData['player_type'] ?? 'non_member';
        $memberId = (int) ($playerData['member_id'] ?? 0);
        $fullNameAr = trim($playerData['full_name_ar'] ?? '');
        $fullNameEn = trim($playerData['full_name_en'] ?? '');
        $dateOfBirth = $playerData['date_of_birth'] ?? null;
        $gender = $playerData['gender'] ?? null;
        $phone = trim($playerData['phone'] ?? '');
        $guardianName = trim($playerData['guardian_name'] ?? '');
        $guardianPhone = trim($playerData['guardian_phone'] ?? '');
        $guardianNationalId = trim($playerData['guardian_national_id'] ?? '');
        $guardianRelationship = trim($playerData['guardian_relationship'] ?? '');

        if ($nationalId !== '' && strlen($nationalId) === 14) {
            $parsed = NationalIdParser::parse($nationalId);
            if ($parsed['is_valid']) {
                $dateOfBirth = $dateOfBirth ?: $parsed['dob'];
                $gender = $gender ?: $parsed['gender'];
            }
        }

        $existingPlayer = null;
        if ($nationalId !== '') {
            $existingPlayer = $db->selectOne(
                "SELECT * FROM sa_players WHERE national_id = ? AND is_archived = 0",
                [$nationalId]
            );
        }
        if (!$existingPlayer && $playerType === 'member' && $memberId > 0) {
            $shouldUseMemberFallback = ($nationalId === '');
            if (!$shouldUseMemberFallback) {
                $memberRecord = $db->selectOne(
                    "SELECT national_id FROM members WHERE id = ? AND is_archived = 0",
                    [$memberId]
                );
                $shouldUseMemberFallback = $memberRecord && $memberRecord['national_id'] === $nationalId;
            }
            if ($shouldUseMemberFallback) {
                $existingPlayer = $db->selectOne(
                    "SELECT * FROM sa_players WHERE member_id = ? AND is_archived = 0",
                    [$memberId]
                );
            }
        }

        if ($existingPlayer) {
            $playerId = (int) $existingPlayer['id'];
            $updateData = ['updated_at' => date('Y-m-d H:i:s')];
            if ($fullNameAr !== '' && $existingPlayer['full_name_ar'] !== $fullNameAr) {
                $updateData['full_name_ar'] = $fullNameAr;
            }
            if ($phone !== '' && ($existingPlayer['phone'] ?? '') !== $phone) {
                $updateData['phone'] = $phone;
            }
            if ($guardianName !== '' && ($existingPlayer['guardian_name'] ?? '') !== $guardianName) {
                $updateData['guardian_name'] = $guardianName;
                $updateData['guardian_phone'] = $guardianPhone ?: $existingPlayer['guardian_phone'];
            }
            if (count($updateData) > 1) {
                $db->update('sa_players', $updateData, 'id = ?', [$playerId]);
            }
        } else {
            if ($fullNameAr === '') {
                return ['success' => false, 'error' => 'الاسم بالعربي مطلوب'];
            }

            $maxSerial = $db->selectOne(
                "SELECT MAX(CAST(SUBSTRING(registration_serial, 5) AS UNSIGNED)) as max_num FROM sa_players WHERE registration_serial LIKE 'SAP-%'"
            );
            $nextNum = ((int) ($maxSerial['max_num'] ?? 0)) + 1;
            $serialNumber = 'SAP-' . str_pad((string) $nextNum, 5, '0', STR_PAD_LEFT);

            $playerId = $db->insert('sa_players', [
                'registration_serial'   => $serialNumber,
                'full_name_ar'          => $fullNameAr,
                'full_name_en'          => $fullNameEn ?: null,
                'player_type'           => $playerType,
                'member_id'             => $memberId > 0 ? $memberId : null,
                'national_id'           => $nationalId ?: null,
                'date_of_birth'         => $dateOfBirth ?: null,
                'gender'                => $gender ?: null,
                'phone'                 => $phone ?: null,
                'guardian_name'         => $guardianName ?: null,
                'guardian_phone'        => $guardianPhone ?: null,
                'guardian_national_id'  => $guardianNationalId ?: null,
                'guardian_relationship' => $guardianRelationship ?: null,
                'medical_status'        => 'pending',
                'card_status'           => 'inactive',
                'branch_id'             => $branch ? (int) $branch['id'] : null,
                'created_at'            => date('Y-m-d H:i:s'),
                'updated_at'            => date('Y-m-d H:i:s'),
                'created_by'            => $employee ? (int) $employee->id : null,
            ]);
        }

        $fees = self::calculateFees($playerType);
        $registrationNumber = self::generateRegistrationNumber();

        $formAlreadyPaid = false;
        if ($existingPlayer && (int) ($existingPlayer['registration_fee_paid'] ?? 0) === 1) {
            $formAlreadyPaid = true;
        }

        $registrationId = $db->insert('sa_registrations', [
            'registration_number'  => $registrationNumber,
            'player_id'            => $playerId,
            'player_type'          => $playerType,
            'member_id'            => $memberId > 0 ? $memberId : null,
            'national_id'          => $nationalId ?: null,
            'status'               => 'in_progress',
            'payment_status'       => 'unpaid',
            'registration_fee'     => $formAlreadyPaid ? 0 : $fees['registration_fee'],
            'card_fee'             => 0,
            'form_fee'             => 0,
            'total_fees'           => $formAlreadyPaid ? 0 : $fees['total_fees'],
            'form_payment_status'  => $formAlreadyPaid ? 'paid' : 'unpaid',
            'branch_id'            => $branch ? (int) $branch['id'] : null,
            'created_by'           => $employee ? (int) $employee->id : null,
            'created_at'           => date('Y-m-d H:i:s'),
            'updated_at'           => date('Y-m-d H:i:s'),
        ]);

        return [
            'success'             => true,
            'registration_id'     => $registrationId,
            'registration_number' => $registrationNumber,
            'player_id'           => $playerId,
            'fees'                => $fees,
            'form_already_paid'   => $formAlreadyPaid,
        ];
    }

    public static function capturePhoto(int $registrationId, array $file): array
    {
        $db = App::getInstance()->db();

        $registration = $db->selectOne(
            "SELECT * FROM sa_registrations WHERE id = ? AND status = 'in_progress'",
            [$registrationId]
        );
        if (!$registration) {
            return ['success' => false, 'error' => 'التسجيل غير موجود أو مكتمل'];
        }

        $playerId = (int) $registration['player_id'];
        $result = PhotoUploadService::upload($file, 'sa_players', $playerId);
        if (!$result) {
            return ['success' => false, 'error' => 'فشل رفع الصورة'];
        }

        $db->update('sa_players', [
            'photo_path'  => $result['path'],
            'updated_at'  => date('Y-m-d H:i:s'),
        ], 'id = ?', [$playerId]);

        $db->update('sa_registrations', [
            'photo_captured' => 1,
            'updated_at'     => date('Y-m-d H:i:s'),
        ], 'id = ?', [$registrationId]);

        return [
            'success'    => true,
            'photo_path' => $result['path'],
            'thumbnail'  => $result['thumbnail_path'],
        ];
    }

    public static function selectGroup(int $registrationId, int $groupId, int $months = 1, bool $hasSibling = false): array
    {
        $db = App::getInstance()->db();

        $registration = $db->selectOne(
            "SELECT * FROM sa_registrations WHERE id = ? AND status = 'in_progress'",
            [$registrationId]
        );
        if (!$registration) {
            return ['success' => false, 'error' => 'التسجيل غير موجود أو مكتمل'];
        }

        $group = $db->selectOne(
            "SELECT * FROM sa_groups WHERE id = ? AND status = 'active' AND is_archived = 0",
            [$groupId]
        );
        if (!$group) {
            return ['success' => false, 'error' => 'المجموعة غير موجودة أو غير نشطة'];
        }

        $program = $db->selectOne(
            "SELECT monthly_fee_member, monthly_fee_nonmember, max_capacity FROM sa_programs WHERE id = ?",
            [(int) $group['program_id']]
        );
        if (!$program) {
            return ['success' => false, 'error' => 'البرنامج المرتبط بالمجموعة غير موجود'];
        }

        if ((int) $group['current_count'] >= (int) $program['max_capacity']) {
            return ['success' => false, 'error' => 'المجموعة ممتلئة'];
        }

        $playerType = $registration['player_type'];
        $monthlyFee = $playerType === 'member'
            ? (float) $program['monthly_fee_member']
            : (float) $program['monthly_fee_nonmember'];

        $subscriptionAmount = $monthlyFee * max(1, $months);

        // Resolve academy code for discount scoping
        $academyCode = null;
        if (!empty($program['academy_id'])) {
            $academy = $db->selectOne("SELECT code FROM sa_academies WHERE id = ?", [(int) $program['academy_id']]);
            $academyCode = $academy['code'] ?? null;
        }

        $discountResult = DiscountCalculatorService::calculateDiscounts(
            $subscriptionAmount,
            $months,
            $hasSibling,
            $academyCode
        );

        $subscriptionAfterDiscount = $discountResult['final_amount'];

        $totalFees = (float) $registration['registration_fee']
                   + (float) $registration['card_fee']
                   + (float) $registration['form_fee']
                   + $subscriptionAfterDiscount;

        $db->update('sa_registrations', [
            'group_id'             => $groupId,
            'subscription_amount'  => $subscriptionAfterDiscount,
            'subscription_months'  => $months,
            'total_fees'           => $totalFees,
            'updated_at'           => date('Y-m-d H:i:s'),
        ], 'id = ?', [$registrationId]);

        return [
            'success'             => true,
            'group_name'          => $group['name_ar'],
            'monthly_fee'         => $monthlyFee,
            'months'              => $months,
            'subscription_before_discount' => $subscriptionAmount,
            'discounts'           => $discountResult['discounts'],
            'total_discount'      => $discountResult['total_discount'],
            'subscription_amount' => $subscriptionAfterDiscount,
            'total_fees'          => $totalFees,
        ];
    }

    public static function selectProgram(int $registrationId, int $programId, int $months = 1, bool $hasSibling = false): array
    {
        $db = App::getInstance()->db();

        $registration = $db->selectOne(
            "SELECT * FROM sa_registrations WHERE id = ? AND status = 'in_progress'",
            [$registrationId]
        );
        if (!$registration) {
            return ['success' => false, 'error' => 'التسجيل غير موجود أو مكتمل'];
        }

        $groupResult = EnrollmentService::findOrCreateAvailableGroup($programId);
        if (!$groupResult['success']) {
            return $groupResult;
        }

        $group = $groupResult['group'];
        $groupId = (int) $group['id'];

        return self::selectGroup($registrationId, $groupId, $months, $hasSibling);
    }

    public static function calculateFees(string $playerType): array
    {
        $fee = $playerType === 'member' ? 50.0 : 100.0;
        return [
            'registration_fee' => $fee,
            'card_fee'         => 0.0,
            'form_fee'         => 0.0,
            'total_fees'       => $fee,
        ];
    }

    public static function submitFormPayment(int $registrationId): array
    {
        $db = App::getInstance()->db();

        $registration = $db->selectOne(
            "SELECT r.*, p.full_name_ar, p.member_id
             FROM sa_registrations r
             INNER JOIN sa_players p ON p.id = r.player_id
             WHERE r.id = ? AND r.status = 'in_progress'",
            [$registrationId]
        );
        if (!$registration) {
            return ['success' => false, 'error' => 'التسجيل غير موجود أو مكتمل'];
        }

        if ($registration['form_payment_status'] === 'paid') {
            return ['success' => true, 'already_paid' => true];
        }

        $playerFeeCheck = $db->selectOne(
            "SELECT registration_fee_paid FROM sa_players WHERE id = ?",
            [(int) $registration['player_id']]
        );
        if ($playerFeeCheck && (int) ($playerFeeCheck['registration_fee_paid'] ?? 0) === 1) {
            $db->update('sa_registrations', [
                'form_payment_status' => 'paid',
                'registration_fee'    => 0,
                'updated_at'          => date('Y-m-d H:i:s'),
            ], 'id = ?', [$registrationId]);
            return ['success' => true, 'already_paid' => true];
        }

        $totalFee = (float) $registration['total_fees'];
        if ($totalFee <= 0) {
            $totalFee = $registration['player_type'] === 'member' ? 50.0 : 100.0;
        }

        $memberId = (int) ($registration['member_id'] ?? 0);
        $description = 'رسوم تسجيل نشاط رياضي (' . (int) $totalFee . ' ج.م) — ' . ($registration['full_name_ar'] ?? '');

        $result = PaymentRequestService::createRequest([
            'member_id'           => $memberId,
            'payment_type'        => 'sa_registration_fee',
            'amount'              => (string) $totalFee,
            'description_ar'      => $description,
            'related_entity_type' => 'sa_registration_form',
            'related_entity_id'   => $registrationId,
        ]);

        if (!$result['success']) {
            return $result;
        }

        $db->update('sa_registrations', [
            'form_payment_request_id' => (int) $result['request_id'],
            'form_payment_status'     => 'pending',
            'updated_at'              => date('Y-m-d H:i:s'),
        ], 'id = ?', [$registrationId]);

        return [
            'success'        => true,
            'request_id'     => $result['request_id'],
            'request_number' => $result['request_number'],
            'amount'         => $totalFee,
        ];
    }

    public static function saveSelectedDisciplines(int $registrationId, array $disciplineIds): array
    {
        $db = App::getInstance()->db();

        $registration = $db->selectOne(
            "SELECT * FROM sa_registrations WHERE id = ? AND status = 'in_progress'",
            [$registrationId]
        );
        if (!$registration) {
            return ['success' => false, 'error' => 'التسجيل غير موجود أو مكتمل'];
        }

        if (empty($disciplineIds)) {
            return ['success' => false, 'error' => 'يجب اختيار نشاط واحد على الأقل'];
        }

        $disciplines = $db->select(
            "SELECT id, name_ar FROM sa_disciplines WHERE id IN (" . implode(',', array_map('intval', $disciplineIds)) . ") AND is_active = 1 AND is_archived = 0"
        );

        $selected = [];
        foreach ($disciplines as $d) {
            $selected[] = ['id' => (int) $d['id'], 'name' => $d['name_ar']];
        }

        $db->update('sa_registrations', [
            'selected_disciplines' => json_encode($selected, JSON_UNESCAPED_UNICODE),
            'updated_at'           => date('Y-m-d H:i:s'),
        ], 'id = ?', [$registrationId]);

        return ['success' => true, 'selected' => $selected];
    }

    public static function submitToPaymentQueue(int $registrationId): array
    {
        return ['success' => false, 'error' => 'تم إلغاء هذه الخطوة — الدفع يتم في خطوة الاستمارة'];
    }

    public static function generateCard(int $registrationId): array
    {
        $db = App::getInstance()->db();
        $employee = App::getInstance()->currentEmployee();
        $branch = App::getInstance()->currentBranch();

        $registration = $db->selectOne(
            "SELECT r.*, p.photo_path, p.full_name_ar
             FROM sa_registrations r
             INNER JOIN sa_players p ON p.id = r.player_id
             WHERE r.id = ? AND r.payment_status = 'paid'",
            [$registrationId]
        );
        if (!$registration) {
            return ['success' => false, 'error' => 'التسجيل غير موجود أو لم يتم الدفع'];
        }

        $existing = $db->selectOne(
            "SELECT id FROM sa_player_cards WHERE registration_id = ? AND is_archived = 0",
            [$registrationId]
        );
        if ($existing) {
            return ['success' => true, 'card_id' => (int) $existing['id'], 'already_exists' => true];
        }

        $cardNumber = self::generateCardNumber();
        $qrData = QRCodeGenerator::encode('SA:' . $cardNumber);

        $months = max(1, (int) ($registration['subscription_months'] ?? 1));
        $validFrom = date('Y-m-d');
        $validUntil = date('Y-m-d', strtotime("+{$months} months -1 day"));

        $cardId = $db->insert('sa_player_cards', [
            'card_number'     => $cardNumber,
            'player_id'       => (int) $registration['player_id'],
            'registration_id' => $registrationId,
            'card_type'       => 'standard',
            'status'          => 'active',
            'qr_code_data'    => $qrData,
            'valid_from'      => $validFrom,
            'valid_until'     => $validUntil,
            'photo_path'      => $registration['photo_path'],
            'issued_by'       => $employee ? (int) $employee->id : null,
            'branch_id'       => $branch ? (int) $branch['id'] : null,
            'created_at'      => date('Y-m-d H:i:s'),
            'updated_at'      => date('Y-m-d H:i:s'),
        ]);

        $db->update('sa_registrations', [
            'card_generated' => 1,
            'updated_at'     => date('Y-m-d H:i:s'),
        ], 'id = ?', [$registrationId]);

        $db->update('sa_players', [
            'card_status' => 'active',
            'updated_at'  => date('Y-m-d H:i:s'),
        ], 'id = ?', [(int) $registration['player_id']]);

        EventBus::dispatch('sa.card.issued', [
            'card_id'         => $cardId,
            'card_number'     => $cardNumber,
            'player_id'       => (int) $registration['player_id'],
            'registration_id' => $registrationId,
        ]);

        return [
            'success'     => true,
            'card_id'     => $cardId,
            'card_number' => $cardNumber,
        ];
    }

    public static function completeRegistration(int $registrationId, ?int $paymentId = null): array
    {
        $db = App::getInstance()->db();

        $registration = $db->selectOne(
            "SELECT * FROM sa_registrations WHERE id = ?",
            [$registrationId]
        );
        if (!$registration) {
            return ['success' => false, 'error' => 'التسجيل غير موجود'];
        }

        $groupId = (int) ($registration['group_id'] ?? 0);

        $db->beginTransaction();
        try {
            $db->update('sa_registrations', [
                'status'         => 'completed',
                'payment_status' => 'paid',
                'completed_at'   => date('Y-m-d H:i:s'),
                'updated_at'     => date('Y-m-d H:i:s'),
            ], 'id = ?', [$registrationId]);

            $db->update('sa_players', [
                'registration_fee_paid' => 1,
                'updated_at'            => date('Y-m-d H:i:s'),
            ], 'id = ?', [(int) $registration['player_id']]);

            if ($groupId > 0) {
                $existingEnrollment = $db->selectOne(
                    "SELECT id FROM sa_group_players WHERE group_id = ? AND player_id = ? AND status IN ('active','pending_payment')",
                    [$groupId, (int) $registration['player_id']]
                );

                if (!$existingEnrollment) {
                    $employeeId = (int) ($registration['created_by'] ?? 0);
                    $db->insert('sa_group_players', [
                        'group_id'                => $groupId,
                        'player_id'               => (int) $registration['player_id'],
                        'enrolled_at'             => date('Y-m-d'),
                        'status'                  => 'active',
                        'activated_by_payment_id' => $paymentId,
                        'created_at'              => date('Y-m-d H:i:s'),
                        'updated_at'              => date('Y-m-d H:i:s'),
                        'created_by'              => $employeeId,
                    ]);

                    $group = $db->selectOne("SELECT current_count, max_capacity FROM sa_groups WHERE id = ? FOR UPDATE", [$groupId]);
                    $newCount = (int) $group['current_count'] + 1;
                    $db->update('sa_groups', [
                        'current_count' => $newCount,
                        'is_full'       => $newCount >= (int) $group['max_capacity'] ? 1 : 0,
                        'updated_at'    => date('Y-m-d H:i:s'),
                    ], 'id = ?', [$groupId]);
                }
            }

            $db->commit();
        } catch (\Throwable $e) {
            $db->rollBack();
            return ['success' => false, 'error' => 'فشل إتمام التسجيل: ' . $e->getMessage()];
        }

        EventBus::dispatch('sa.registration.completed', [
            'registration_id' => $registrationId,
            'player_id'       => (int) $registration['player_id'],
            'group_id'        => $groupId,
            'total_fees'      => (float) $registration['total_fees'],
        ]);

        return ['success' => true];
    }

    public static function cancelRegistration(int $registrationId, string $reason = ''): array
    {
        $db = App::getInstance()->db();

        $registration = $db->selectOne(
            "SELECT * FROM sa_registrations WHERE id = ? AND status IN ('in_progress', 'pending_payment')",
            [$registrationId]
        );
        if (!$registration) {
            return ['success' => false, 'error' => 'التسجيل غير موجود أو لا يمكن إلغاؤه'];
        }

        $db->update('sa_registrations', [
            'status'        => 'cancelled',
            'cancelled_at'  => date('Y-m-d H:i:s'),
            'cancel_reason' => $reason ?: null,
            'updated_at'    => date('Y-m-d H:i:s'),
        ], 'id = ?', [$registrationId]);

        if (!empty($registration['payment_request_id']) && $registration['payment_status'] === 'pending') {
            PaymentRequestService::cancelRequest((int) $registration['payment_request_id'], $reason ?: 'إلغاء التسجيل');
        }

        return ['success' => true];
    }

    public static function generateRegistrationNumber(): string
    {
        $db = App::getInstance()->db();
        $year = date('Y');
        $prefix = 'SAR-' . $year . '-';

        $row = $db->selectOne(
            "SELECT MAX(CAST(SUBSTRING(registration_number, " . (strlen($prefix) + 1) . ") AS UNSIGNED)) as max_num
             FROM sa_registrations WHERE registration_number LIKE ?",
            [$prefix . '%']
        );

        $next = ((int) ($row['max_num'] ?? 0)) + 1;
        return $prefix . str_pad((string) $next, 6, '0', STR_PAD_LEFT);
    }

    private static function generateCardNumber(): string
    {
        $db = App::getInstance()->db();
        $year = date('Y');
        $prefix = 'SAC-' . $year . '-';

        $row = $db->selectOne(
            "SELECT MAX(CAST(SUBSTRING(card_number, " . (strlen($prefix) + 1) . ") AS UNSIGNED)) as max_num
             FROM sa_player_cards WHERE card_number LIKE ?",
            [$prefix . '%']
        );

        $next = ((int) ($row['max_num'] ?? 0)) + 1;
        return $prefix . str_pad((string) $next, 6, '0', STR_PAD_LEFT);
    }
}
