<?php
declare(strict_types=1);

namespace App\Modules\PlayerAffairs\Controllers;

use App\Core\Controller;
use App\Core\Request;
use App\Core\Response;
use App\Core\App;
use App\Modules\PlayerAffairs\Models\Player;
use App\Modules\PlayerAffairs\Models\AcademyEnrollment;
use App\Modules\PlayerAffairs\Models\PlayerMedicalRecord;
use App\Modules\PlayerAffairs\Services\PlayerRegistrationService;
use App\Modules\PlayerAffairs\Services\PlayerCardService;
use App\Modules\PlayerAffairs\Services\MedicalRecordService;
use App\Modules\Members\Services\NationalIdParser;

class PlayerController extends Controller
{
    /**
     * List all players with tabs, status filter, search, and pagination.
     */
    public function index(Request $request): Response
    {
        $filters = [
            'q'              => trim((string) $request->get('q', '')),
            'player_type'    => trim((string) $request->get('player_type', '')),
            'card_status'    => trim((string) $request->get('card_status', '')),
            'medical_status' => trim((string) $request->get('medical_status', '')),
        ];

        $page = max(1, (int) $request->get('page', 1));
        $result = Player::search($filters, 25, $page);

        return $this->view('PlayerAffairs.Views.index', [
            'players'         => $result['data'],
            'pagination'      => $result['pagination'],
            'filters'         => $filters,
            'playerTypes'     => Player::getPlayerTypes(),
            'cardStatuses'    => Player::getCardStatuses(),
            'medicalStatuses' => Player::getMedicalStatuses(),
        ]);
    }

    /**
     * Show the player registration form.
     */
    public function create(Request $request): Response
    {
        return $this->view('PlayerAffairs.Views.create', [
            'playerTypes'    => Player::getPlayerTypes(),
            'genders'        => Player::getGenders(),
            'relationships'  => Player::getGuardianRelationships(),
        ]);
    }

    /**
     * Validate and register a new player.
     */
    public function store(Request $request): Response
    {
        $playerType = trim((string) $request->post('player_type', ''));
        $fullNameAr = trim((string) $request->post('full_name_ar', ''));
        $fullNameEn = trim((string) $request->post('full_name_en', ''));
        $nationalId = trim((string) $request->post('national_id', ''));
        $passportNumber = trim((string) $request->post('passport_number', ''));
        $dateOfBirth = trim((string) $request->post('date_of_birth', ''));
        $gender = trim((string) $request->post('gender', ''));
        $phone = trim((string) $request->post('phone', ''));
        $email = trim((string) $request->post('email', ''));
        $address = trim((string) $request->post('address', ''));
        $guardianName = trim((string) $request->post('guardian_name', ''));
        $guardianPhone = trim((string) $request->post('guardian_phone', ''));
        $guardianNationalId = trim((string) $request->post('guardian_national_id', ''));
        $guardianRelationship = trim((string) $request->post('guardian_relationship', ''));
        $schoolName = trim((string) $request->post('school_name', ''));
        $schoolGrade = trim((string) $request->post('school_grade', ''));
        $notes = trim((string) $request->post('notes', ''));
        $memberId = $request->post('member_id');

        // Validation
        $errors = [];
        if ($fullNameAr === '' || mb_strlen($fullNameAr) < 2) {
            $errors[] = 'الاسم بالعربي مطلوب (حرفان على الأقل)';
        }
        if (!array_key_exists($playerType, Player::getPlayerTypes())) {
            $errors[] = 'نوع اللاعب غير صالح';
        }
        if ($dateOfBirth === '') {
            $errors[] = 'تاريخ الميلاد مطلوب';
        }
        if ($gender !== '' && !array_key_exists($gender, Player::getGenders())) {
            $errors[] = 'الجنس غير صالح';
        }

        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('/players/create');
        }

        $data = [
            'full_name_ar'          => $fullNameAr,
            'full_name_en'          => $fullNameEn ?: null,
            'national_id'           => $nationalId ?: null,
            'passport_number'       => $passportNumber ?: null,
            'date_of_birth'         => $dateOfBirth,
            'gender'                => $gender ?: null,
            'phone'                 => $phone ?: null,
            'email'                 => $email ?: null,
            'address'               => $address ?: null,
            'guardian_name'         => $guardianName ?: null,
            'guardian_phone'        => $guardianPhone ?: null,
            'guardian_national_id'  => $guardianNationalId ?: null,
            'guardian_relationship' => $guardianRelationship ?: null,
            'school_name'           => $schoolName ?: null,
            'school_grade'          => $schoolGrade ?: null,
            'notes'                 => $notes ?: null,
        ];

        // Handle photo upload
        $photoPath = self::handlePhotoUpload();
        if ($photoPath) {
            $data['photo_path'] = $photoPath;
        }

        try {
            if ($playerType === 'member' && $memberId) {
                $player = PlayerRegistrationService::registerMemberPlayer((int) $memberId, $data);
            } else {
                $player = PlayerRegistrationService::registerNonMemberPlayer($data);
            }
        } catch (\RuntimeException $e) {
            $session = App::getInstance()->session();
            $session->flash('_alerts', [['type' => 'error', 'message' => $e->getMessage()]]);
            $session->flash('_old_input', $request->all());
            return $this->redirect('/players/create');
        }

        return $this->redirect('/players/' . $player->id)->withSuccess('تم تسجيل اللاعب بنجاح');
    }

    /**
     * Show a player's full profile.
     */
    public function show(Request $request, string $id): Response
    {
        $player = Player::find((int) $id);
        if (!$player) {
            return $this->redirect('/players')->withError('اللاعب غير موجود');
        }

        $db = App::getInstance()->db();
        $disciplines = $db->select(
            "SELECT DISTINCT sd.id, sd.name_ar AS discipline_name, sd.icon,
                    a.name_ar AS academy_name, ae.season, ae.status
             FROM academy_enrollments ae
             JOIN academies a ON a.id = ae.academy_id
             JOIN sport_disciplines sd ON sd.id = a.discipline_id
             WHERE ae.player_id = ? AND ae.status IN ('active', 'suspended')
             ORDER BY sd.name_ar",
            [(int) $id]
        );
        $enrollments    = AcademyEnrollment::getForPlayer((int) $id);
        $medicalRecords = PlayerMedicalRecord::getForPlayer((int) $id);

        $history = self::buildPlayerHistory($db, (int) $id);

        return $this->view('PlayerAffairs.Views.show', [
            'player'         => $player,
            'disciplines'    => $disciplines,
            'enrollments'    => $enrollments,
            'medicalRecords' => $medicalRecords,
            'history'        => $history,
            'cardStatuses'   => Player::getCardStatuses(),
            'medicalStatuses' => Player::getMedicalStatuses(),
            'playerTypes'    => Player::getPlayerTypes(),
            'genders'        => Player::getGenders(),
        ]);
    }

    /**
     * Show the edit form for a player.
     */
    public function edit(Request $request, string $id): Response
    {
        $player = Player::find((int) $id);
        if (!$player) {
            return $this->redirect('/players')->withError('اللاعب غير موجود');
        }

        return $this->view('PlayerAffairs.Views.edit', [
            'player'        => $player,
            'playerTypes'   => Player::getPlayerTypes(),
            'genders'       => Player::getGenders(),
            'relationships' => Player::getGuardianRelationships(),
        ]);
    }

    /**
     * Update player information.
     */
    public function update(Request $request, string $id): Response
    {
        $player = Player::find((int) $id);
        if (!$player) {
            return $this->redirect('/players')->withError('اللاعب غير موجود');
        }

        $fullNameAr = trim((string) $request->post('full_name_ar', ''));
        $fullNameEn = trim((string) $request->post('full_name_en', ''));
        $nationalId = trim((string) $request->post('national_id', ''));
        $passportNumber = trim((string) $request->post('passport_number', ''));
        $dateOfBirth = trim((string) $request->post('date_of_birth', ''));
        $gender = trim((string) $request->post('gender', ''));
        $phone = trim((string) $request->post('phone', ''));
        $email = trim((string) $request->post('email', ''));
        $address = trim((string) $request->post('address', ''));
        $guardianName = trim((string) $request->post('guardian_name', ''));
        $guardianPhone = trim((string) $request->post('guardian_phone', ''));
        $guardianNationalId = trim((string) $request->post('guardian_national_id', ''));
        $guardianRelationship = trim((string) $request->post('guardian_relationship', ''));
        $schoolName = trim((string) $request->post('school_name', ''));
        $schoolGrade = trim((string) $request->post('school_grade', ''));
        $notes = trim((string) $request->post('notes', ''));

        // Validation
        $errors = [];
        if ($fullNameAr === '' || mb_strlen($fullNameAr) < 2) {
            $errors[] = 'الاسم بالعربي مطلوب (حرفان على الأقل)';
        }
        if ($dateOfBirth === '') {
            $errors[] = 'تاريخ الميلاد مطلوب';
        }

        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('/players/' . $id . '/edit');
        }

        $updateData = [
            'full_name_ar'          => $fullNameAr,
            'full_name_en'          => $fullNameEn ?: null,
            'national_id'           => $nationalId ?: null,
            'passport_number'       => $passportNumber ?: null,
            'date_of_birth'         => $dateOfBirth,
            'gender'                => $gender ?: null,
            'phone'                 => $phone ?: null,
            'email'                 => $email ?: null,
            'address'               => $address ?: null,
            'guardian_name'         => $guardianName ?: null,
            'guardian_phone'        => $guardianPhone ?: null,
            'guardian_national_id'  => $guardianNationalId ?: null,
            'guardian_relationship' => $guardianRelationship ?: null,
            'school_name'           => $schoolName ?: null,
            'school_grade'          => $schoolGrade ?: null,
            'notes'                 => $notes ?: null,
        ];

        $photoPath = self::handlePhotoUpload();
        if ($photoPath) {
            $updateData['photo_path'] = $photoPath;
        }

        $player->update($updateData);

        return $this->redirect('/players/' . $id)->withSuccess('تم تحديث بيانات اللاعب بنجاح');
    }

    /**
     * Activate a player's card.
     */
    public function activateCard(Request $request, string $id): Response
    {
        try {
            PlayerCardService::activateCard((int) $id);
        } catch (\RuntimeException $e) {
            return $this->redirect('/players/' . $id)->withError($e->getMessage());
        }

        return $this->redirect('/players/' . $id)->withSuccess('تم تفعيل الكارنيه بنجاح');
    }

    /**
     * Suspend a player's card.
     */
    public function suspendCard(Request $request, string $id): Response
    {
        $reason = trim((string) $request->post('reason', ''));

        try {
            PlayerCardService::suspendCard((int) $id, $reason ?: null);
        } catch (\RuntimeException $e) {
            return $this->redirect('/players/' . $id)->withError($e->getMessage());
        }

        return $this->redirect('/players/' . $id)->withSuccess('تم إيقاف الكارنيه');
    }

    /**
     * Revoke a player's card.
     */
    public function revokeCard(Request $request, string $id): Response
    {
        try {
            PlayerCardService::revokeCard((int) $id);
        } catch (\RuntimeException $e) {
            return $this->redirect('/players/' . $id)->withError($e->getMessage());
        }

        return $this->redirect('/players/' . $id)->withSuccess('تم إلغاء الكارنيه');
    }

    /**
     * Add a medical record for a player.
     */
    public function addMedical(Request $request, string $id): Response
    {
        $data = [
            'record_type'       => trim((string) $request->post('record_type', '')),
            'certificate_type'  => trim((string) $request->post('certificate_type', 'recreational')),
            'exam_date'         => trim((string) $request->post('exam_date', '')),
            'expiry_date'       => trim((string) $request->post('expiry_date', '')) ?: null,
            'doctor_name'       => trim((string) $request->post('doctor_name', '')) ?: null,
            'clinic_name'       => trim((string) $request->post('clinic_name', '')) ?: null,
            'issuing_authority' => trim((string) $request->post('issuing_authority', '')) ?: null,
            'cert_number'       => trim((string) $request->post('cert_number', '')) ?: null,
            'restrictions'      => trim((string) $request->post('restrictions', '')) ?: null,
            'document_id'       => $request->post('document_id') ? (int) $request->post('document_id') : null,
            'notes'             => trim((string) $request->post('notes', '')) ?: null,
        ];

        $errors = [];
        if (!array_key_exists($data['record_type'], PlayerMedicalRecord::getRecordTypes())) {
            $errors[] = 'نوع السجل الطبي غير صالح';
        }
        if (!array_key_exists($data['certificate_type'], PlayerMedicalRecord::getCertificateTypes())) {
            $errors[] = 'نوع الشهادة غير صالح';
        }
        if (empty($data['exam_date'])) {
            $errors[] = 'تاريخ الفحص مطلوب';
        }

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

        try {
            MedicalRecordService::addRecord((int) $id, $data);
        } catch (\RuntimeException $e) {
            return $this->redirect('/players/' . $id)->withError($e->getMessage());
        }

        return $this->redirect('/players/' . $id)->withSuccess('تم رفع السجل الطبي بنجاح — في انتظار اعتماد مجلس الأمناء');
    }

    /**
     * Enroll a player in an academy.
     */
    public function enroll(Request $request, string $id): Response
    {
        $player = Player::find((int) $id);
        if (!$player) {
            return $this->redirect('/players')->withError('اللاعب غير موجود');
        }

        $academyId  = (int) $request->post('academy_id', 0);
        $levelId    = $request->post('level_id') ? (int) $request->post('level_id') : null;
        $scheduleId = $request->post('schedule_id') ? (int) $request->post('schedule_id') : null;
        $season     = trim((string) $request->post('season', ''));

        if ($academyId <= 0) {
            return $this->redirect('/players/' . $id)->withError('يجب اختيار أكاديمية');
        }

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

        AcademyEnrollment::create([
            'player_id'      => (int) $id,
            'academy_id'     => $academyId,
            'level_id'       => $levelId,
            'schedule_id'    => $scheduleId,
            'season'         => $season ?: null,
            'enrolled_at'    => date('Y-m-d H:i:s'),
            'enrollment_day' => (int) date('j'),
            'status'         => 'active',
            'created_by'     => $employee ? (int) $employee->id : null,
        ]);

        return $this->redirect('/players/' . $id)->withSuccess('تم تسجيل اللاعب في الأكاديمية بنجاح');
    }

    /**
     * Drop (withdraw) a player from an academy enrollment.
     */
    public function dropEnrollment(Request $request, string $id): Response
    {
        $enrollmentId = (int) $request->post('enrollment_id', 0);
        $droppedReason = trim((string) $request->post('dropped_reason', ''));

        if ($enrollmentId <= 0) {
            return $this->redirect('/players/' . $id)->withError('يجب تحديد التسجيل');
        }

        $enrollment = AcademyEnrollment::find($enrollmentId);
        if (!$enrollment || (int) $enrollment->player_id !== (int) $id) {
            return $this->redirect('/players/' . $id)->withError('التسجيل غير موجود');
        }

        $enrollment->update([
            'status'         => 'dropped',
            'dropped_at'     => date('Y-m-d H:i:s'),
            'dropped_reason' => $droppedReason ?: null,
        ]);

        return $this->redirect('/players/' . $id)->withSuccess('تم انسحاب اللاعب من الأكاديمية');
    }

    /**
     * Parse a National ID and return extracted data (DOB, age, gender, governorate).
     */
    public function parseNid(Request $request): Response
    {
        $nid = trim((string) $request->post('national_id', ''));

        if ($nid === '') {
            return $this->json(['is_valid' => false, 'errors' => ['الرقم القومي مطلوب']]);
        }

        $parsed = NationalIdParser::parse($nid);

        if ($parsed['is_valid']) {
            $db = App::getInstance()->db();
            $dup = $db->selectOne(
                "SELECT id, full_name_ar, registration_serial FROM players WHERE national_id = ? AND is_archived = 0",
                [$nid]
            );
            if ($dup) {
                $parsed['duplicate'] = [
                    'type'   => 'player',
                    'id'     => (int) $dup['id'],
                    'name'   => $dup['full_name_ar'],
                    'serial' => $dup['registration_serial'] ?? '',
                ];
            }
        }

        return $this->json($parsed);
    }

    /**
     * Build a unified timeline of all player activity.
     */
    private static function buildPlayerHistory(\App\Core\Database $db, int $playerId): array
    {
        $events = [];

        // Registration
        $player = $db->selectOne("SELECT created_at, registration_serial FROM players WHERE id = ?", [$playerId]);
        if ($player && $player['created_at']) {
            $events[] = [
                'date'  => $player['created_at'],
                'type'  => 'registration',
                'icon'  => 'user-plus',
                'color' => '#059669',
                'title' => 'تسجيل اللاعب',
                'desc'  => 'تم تسجيل اللاعب بمسلسل: ' . ($player['registration_serial'] ?? '—'),
            ];
        }

        // Enrollments
        $enrollments = $db->select(
            "SELECT ae.enrolled_at, ae.dropped_at, ae.status, ae.dropped_reason, a.name_ar AS academy_name
             FROM academy_enrollments ae
             LEFT JOIN academies a ON a.id = ae.academy_id
             WHERE ae.player_id = ?
             ORDER BY ae.enrolled_at DESC",
            [$playerId]
        );
        foreach ($enrollments as $e) {
            $events[] = [
                'date'  => $e['enrolled_at'],
                'type'  => 'enrollment',
                'icon'  => 'book-open',
                'color' => '#0284C7',
                'title' => 'تسجيل في أكاديمية: ' . ($e['academy_name'] ?? '—'),
                'desc'  => '',
            ];
            if ($e['dropped_at']) {
                $events[] = [
                    'date'  => $e['dropped_at'],
                    'type'  => 'drop',
                    'icon'  => 'log-out',
                    'color' => '#DC2626',
                    'title' => 'انسحاب من: ' . ($e['academy_name'] ?? '—'),
                    'desc'  => $e['dropped_reason'] ?? '',
                ];
            }
        }

        // Subscriptions (payments)
        $subs = $db->select(
            "SELECT asub.subscription_month, asub.total_amount, asub.status, asub.paid_at,
                    sd.name_ar AS discipline_name
             FROM activity_subscriptions asub
             LEFT JOIN sport_disciplines sd ON sd.id = asub.discipline_id
             WHERE asub.player_id = ? AND asub.status = 'paid'
             ORDER BY asub.paid_at DESC
             LIMIT 20",
            [$playerId]
        );
        foreach ($subs as $s) {
            $events[] = [
                'date'  => $s['paid_at'] ?? $s['subscription_month'] . '-01',
                'type'  => 'payment',
                'icon'  => 'credit-card',
                'color' => '#059669',
                'title' => 'سداد اشتراك ' . ($s['discipline_name'] ?? '') . ' — ' . ($s['subscription_month'] ?? ''),
                'desc'  => money($s['total_amount'] ?? '0'),
            ];
        }

        // Medical records
        $medicals = $db->select(
            "SELECT exam_date, record_type, result, doctor_name FROM player_medical_records WHERE player_id = ? ORDER BY exam_date DESC LIMIT 10",
            [$playerId]
        );
        $resultLabels = ['fit' => 'لائق', 'conditional' => 'لائق بشروط', 'unfit' => 'غير لائق'];
        foreach ($medicals as $m) {
            $events[] = [
                'date'  => $m['exam_date'] . ' 00:00:00',
                'type'  => 'medical',
                'icon'  => 'heart-pulse',
                'color' => '#7C3AED',
                'title' => 'فحص طبي — ' . ($resultLabels[$m['result']] ?? $m['result'] ?? ''),
                'desc'  => $m['doctor_name'] ?? '',
            ];
        }

        // Attendance summary (last 5 recorded days)
        $attendance = $db->select(
            "SELECT pa.attendance_date, pa.status, a.name_ar AS academy_name
             FROM player_attendance pa
             LEFT JOIN academy_enrollments ae ON ae.id = pa.enrollment_id
             LEFT JOIN academies a ON a.id = ae.academy_id
             WHERE pa.player_id = ?
             ORDER BY pa.attendance_date DESC
             LIMIT 10",
            [$playerId]
        );
        foreach ($attendance as $att) {
            $statusLabels = ['present' => 'حضور', 'absent' => 'غياب', 'late' => 'تأخير', 'excused' => 'إذن'];
            $events[] = [
                'date'  => $att['attendance_date'] . ' 00:00:00',
                'type'  => 'attendance',
                'icon'  => 'calendar-check',
                'color' => $att['status'] === 'present' ? '#059669' : '#D97706',
                'title' => ($statusLabels[$att['status']] ?? $att['status']) . ' — ' . ($att['academy_name'] ?? ''),
                'desc'  => '',
            ];
        }

        usort($events, fn($a, $b) => strcmp($b['date'], $a['date']));

        return array_slice($events, 0, 30);
    }

    /**
     * Handle profile photo upload. Returns relative path or null.
     */
    private static function handlePhotoUpload(): ?string
    {
        if (empty($_FILES['photo']) || $_FILES['photo']['error'] !== UPLOAD_ERR_OK) {
            return null;
        }

        $file = $_FILES['photo'];
        $allowed = ['image/jpeg', 'image/png', 'image/webp'];
        $finfo = finfo_open(FILEINFO_MIME_TYPE);
        $mime = finfo_file($finfo, $file['tmp_name']);
        finfo_close($finfo);

        if (!in_array($mime, $allowed)) {
            return null;
        }

        if ($file['size'] > 5 * 1024 * 1024) {
            return null;
        }

        $ext = match ($mime) {
            'image/jpeg' => 'jpg',
            'image/png'  => 'png',
            'image/webp' => 'webp',
            default      => 'jpg',
        };

        $uploadDir = App::getInstance()->basePath() . '/storage/uploads/players/';
        if (!is_dir($uploadDir)) {
            mkdir($uploadDir, 0755, true);
        }

        $filename = 'player_' . time() . '_' . bin2hex(random_bytes(4)) . '.' . $ext;

        if (move_uploaded_file($file['tmp_name'], $uploadDir . $filename)) {
            return 'storage/uploads/players/' . $filename;
        }

        return null;
    }

    /**
     * API: Get academies with their levels and schedules for cascading dropdowns.
     */
    public function apiAcademies(Request $request): Response
    {
        $db = App::getInstance()->db();
        $disciplineId = $request->get('discipline_id') ? (int) $request->get('discipline_id') : null;

        $where = 'a.is_active = 1';
        $params = [];
        if ($disciplineId) {
            $where .= ' AND a.discipline_id = ?';
            $params[] = $disciplineId;
        }

        $academies = $db->select(
            "SELECT a.id, a.name_ar, a.discipline_id, sd.name_ar AS discipline_name
             FROM academies a
             LEFT JOIN sport_disciplines sd ON sd.id = a.discipline_id
             WHERE {$where}
             ORDER BY sd.name_ar, a.name_ar",
            $params
        );

        $levels = $db->select(
            "SELECT al.id, al.academy_id, al.name_ar
             FROM academy_levels al
             JOIN academies a ON a.id = al.academy_id
             WHERE a.is_active = 1
             ORDER BY al.sort_order, al.name_ar"
        );

        $schedules = $db->select(
            "SELECT acs.id, acs.academy_id, acs.level_id, acs.day_of_week, acs.start_time, acs.end_time,
                    f.name_ar AS facility_name
             FROM academy_schedules acs
             LEFT JOIN facilities f ON f.id = acs.facility_id
             JOIN academies a ON a.id = acs.academy_id
             WHERE a.is_active = 1
             ORDER BY acs.day_of_week, acs.start_time"
        );

        return $this->json([
            'academies' => $academies,
            'levels'    => $levels,
            'schedules' => $schedules,
        ]);
    }
}
