<?php
declare(strict_types=1);

namespace App\Modules\Coaches\Controllers;

use App\Core\Controller;
use App\Core\Request;
use App\Core\Response;
use App\Core\App;
use App\Modules\Coaches\Models\Coach;
use App\Modules\Coaches\Services\CoachService;
use App\Modules\Coaches\Services\CoachSchedulingService;
use App\Modules\Members\Services\NationalIdParser;

class CoachController extends Controller
{
    public function index(Request $request): Response
    {
        $filters = [
            'q'               => trim((string) $request->get('q', '')),
            'employment_type' => trim((string) $request->get('employment_type', '')),
            'payment_model'   => trim((string) $request->get('payment_model', '')),
        ];

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

        return $this->view('Coaches.Views.index', [
            'coaches'         => $result['data'],
            'pagination'      => $result['pagination'],
            'filters'         => $filters,
            'employmentTypes' => Coach::getEmploymentTypes(),
            'paymentModels'   => Coach::getPaymentModels(),
        ]);
    }

    public function create(Request $request): Response
    {
        $db = App::getInstance()->db();
        $disciplines = $db->select(
            "SELECT id, name_ar FROM sport_disciplines WHERE is_active = 1 AND is_archived = 0 ORDER BY name_ar ASC"
        );

        return $this->view('Coaches.Views.create', [
            'disciplines'     => $disciplines,
            'employmentTypes' => Coach::getEmploymentTypes(),
            'paymentModels'   => Coach::getPaymentModels(),
        ]);
    }

    public function store(Request $request): Response
    {
        $nationalId = trim((string) $request->post('national_id', '')) ?: null;
        $dateOfBirth = trim((string) $request->post('date_of_birth', '')) ?: null;
        $gender = trim((string) $request->post('gender', '')) ?: null;

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

        $data = [
            'full_name_ar'       => trim((string) $request->post('full_name_ar', '')),
            'full_name_en'       => trim((string) $request->post('full_name_en', '')) ?: null,
            'code'               => trim((string) $request->post('code', '')),
            'national_id'        => $nationalId,
            'phone'              => trim((string) $request->post('phone', '')) ?: null,
            'email'              => trim((string) $request->post('email', '')) ?: null,
            'date_of_birth'      => $dateOfBirth,
            'gender'             => $gender,
            'bio_ar'             => trim((string) $request->post('bio_ar', '')) ?: null,
            'employment_type'    => trim((string) $request->post('employment_type', 'contract')),
            'max_players_default'=> (int) $request->post('max_players_default', 20),
            'hourly_rate'        => $request->post('hourly_rate', '') !== '' ? (float) $request->post('hourly_rate') : null,
            'session_rate'       => $request->post('session_rate', '') !== '' ? (float) $request->post('session_rate') : null,
            'monthly_rate'       => $request->post('monthly_rate', '') !== '' ? (float) $request->post('monthly_rate') : null,
            'payment_model'      => trim((string) $request->post('payment_model', 'per_session')),
            'is_active'          => 1,
        ];

        $errors = [];
        if ($data['full_name_ar'] === '' || mb_strlen($data['full_name_ar']) < 3) {
            $errors[] = 'اسم المدرب بالعربي مطلوب (3 أحرف على الأقل)';
        }
        if ($nationalId !== null && strlen($nationalId) === 14) {
            $parsed = NationalIdParser::parse($nationalId);
            if (!$parsed['is_valid']) {
                $errors[] = 'الرقم القومي غير صالح: ' . ($parsed['errors'][0] ?? '');
            }
        } elseif ($nationalId !== null && $nationalId !== '' && strlen($nationalId) !== 14) {
            $errors[] = 'الرقم القومي يجب أن يكون 14 رقم';
        }
        if (!array_key_exists($data['employment_type'], Coach::getEmploymentTypes())) {
            $errors[] = 'نوع التوظيف غير صالح';
        }
        if (!array_key_exists($data['payment_model'], Coach::getPaymentModels())) {
            $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('/coaches/create');
        }

        $photoPath = $this->handlePhotoUpload($request);
        if ($photoPath) {
            $data['photo_path'] = $photoPath;
        }

        $certs = $request->post('certifications', []);
        if (!empty($certs) && is_array($certs)) {
            $data['certifications_json'] = json_encode(array_filter($certs), JSON_UNESCAPED_UNICODE);
        }

        $disciplineIds = $request->post('discipline_ids', []);
        if (!is_array($disciplineIds)) {
            $disciplineIds = [];
        }

        $coach = CoachService::createCoach($data, $disciplineIds);

        return $this->redirect('/coaches/' . $coach->id)->withSuccess('تم إضافة المدرب بنجاح');
    }

    public function show(Request $request, string $id): Response
    {
        $coach = Coach::find((int) $id);
        if (!$coach) {
            return $this->redirect('/coaches')->withError('المدرب غير موجود');
        }

        $db = App::getInstance()->db();
        $academies = $db->select(
            "SELECT id, name_ar FROM academies WHERE is_active = 1 AND is_archived = 0 ORDER BY name_ar ASC"
        );
        $levels = $db->select(
            "SELECT id, academy_id, name_ar FROM academy_levels WHERE is_active = 1 ORDER BY level_order ASC"
        );

        $utilization = CoachSchedulingService::getUtilization((int) $id, date('Y-m-01'), date('Y-m-t'));

        return $this->view('Coaches.Views.show', [
            'coach'        => $coach,
            'disciplines'  => $coach->getDisciplines(),
            'assignments'  => $coach->getAcademyAssignments(),
            'availability' => $coach->getAvailability(),
            'utilization'  => $utilization,
            'academies'    => $academies,
            'levels'       => $levels,
            'roles'        => Coach::getRoles(),
            'dayNames'     => self::getDayNames(),
        ]);
    }

    public function edit(Request $request, string $id): Response
    {
        $coach = Coach::find((int) $id);
        if (!$coach) {
            return $this->redirect('/coaches')->withError('المدرب غير موجود');
        }

        $db = App::getInstance()->db();
        $disciplines = $db->select(
            "SELECT id, name_ar FROM sport_disciplines WHERE is_active = 1 AND is_archived = 0 ORDER BY name_ar ASC"
        );
        $coachDisciplineIds = array_column($coach->getDisciplines(), 'discipline_id');

        return $this->view('Coaches.Views.edit', [
            'coach'              => $coach,
            'disciplines'        => $disciplines,
            'coachDisciplineIds' => $coachDisciplineIds,
            'employmentTypes'    => Coach::getEmploymentTypes(),
            'paymentModels'      => Coach::getPaymentModels(),
        ]);
    }

    public function update(Request $request, string $id): Response
    {
        $coach = Coach::find((int) $id);
        if (!$coach) {
            return $this->redirect('/coaches')->withError('المدرب غير موجود');
        }

        $nationalId = trim((string) $request->post('national_id', '')) ?: null;
        $dateOfBirth = trim((string) $request->post('date_of_birth', '')) ?: null;
        $gender = trim((string) $request->post('gender', '')) ?: null;

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

        $data = [
            'full_name_ar'       => trim((string) $request->post('full_name_ar', '')),
            'full_name_en'       => trim((string) $request->post('full_name_en', '')) ?: null,
            'code'               => trim((string) $request->post('code', '')),
            'national_id'        => $nationalId,
            'phone'              => trim((string) $request->post('phone', '')) ?: null,
            'email'              => trim((string) $request->post('email', '')) ?: null,
            'date_of_birth'      => $dateOfBirth,
            'gender'             => $gender,
            'bio_ar'             => trim((string) $request->post('bio_ar', '')) ?: null,
            'employment_type'    => trim((string) $request->post('employment_type', 'contract')),
            'max_players_default'=> (int) $request->post('max_players_default', 20),
            'hourly_rate'        => $request->post('hourly_rate', '') !== '' ? (float) $request->post('hourly_rate') : null,
            'session_rate'       => $request->post('session_rate', '') !== '' ? (float) $request->post('session_rate') : null,
            'monthly_rate'       => $request->post('monthly_rate', '') !== '' ? (float) $request->post('monthly_rate') : null,
            'payment_model'      => trim((string) $request->post('payment_model', 'per_session')),
        ];

        if ($data['code'] === '') {
            $base = $data['full_name_en'] ?? $data['full_name_ar'] ?? 'COACH';
            $code = strtoupper(preg_replace('/[^A-Z0-9]/i', '_', $base));
            $data['code'] = 'C_' . substr($code, 0, 20) . '_' . time() % 10000;
        }
        $data['code'] = strtoupper($data['code']);

        $errors = [];
        if ($data['full_name_ar'] === '' || mb_strlen($data['full_name_ar']) < 3) {
            $errors[] = 'اسم المدرب بالعربي مطلوب (3 أحرف على الأقل)';
        }

        $existing = Coach::query()
            ->where('code', '=', $data['code'])
            ->whereRaw('`id` != ?', [(int) $id])
            ->first();
        if ($existing) {
            $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('/coaches/' . $id . '/edit');
        }

        $photoPath = $this->handlePhotoUpload($request);
        if ($photoPath) {
            $data['photo_path'] = $photoPath;
        }

        $certs = $request->post('certifications', []);
        if (is_array($certs)) {
            $data['certifications_json'] = json_encode(array_filter($certs), JSON_UNESCAPED_UNICODE);
        }

        $coach->update($data);

        $disciplineIds = $request->post('discipline_ids', []);
        if (is_array($disciplineIds)) {
            CoachService::syncDisciplines((int) $id, $disciplineIds);
        }

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

    public function toggle(Request $request, string $id): Response
    {
        $coach = Coach::find((int) $id);
        if (!$coach) {
            return $this->redirect('/coaches')->withError('المدرب غير موجود');
        }

        $newStatus = $coach->is_active ? 0 : 1;
        $coach->update(['is_active' => $newStatus]);

        $message = $newStatus ? 'تم تفعيل المدرب' : 'تم إيقاف المدرب';
        return $this->redirect('/coaches/' . $id)->withSuccess($message);
    }

    public function assign(Request $request, string $id): Response
    {
        $coach = Coach::find((int) $id);
        if (!$coach) {
            return $this->redirect('/coaches')->withError('المدرب غير موجود');
        }

        $academyId  = (int) $request->post('academy_id', 0);
        $levelId    = $request->post('level_id', '') !== '' ? (int) $request->post('level_id') : null;
        $role       = trim((string) $request->post('role', 'coach'));
        $maxPlayers = $request->post('max_players', '') !== '' ? (int) $request->post('max_players') : null;
        $from       = trim((string) $request->post('assigned_from', date('Y-m-d')));

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

        CoachService::assignToAcademy((int) $id, $academyId, $levelId, $role, $maxPlayers, $from);

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

    public function unassign(Request $request, string $id): Response
    {
        $assignmentId = (int) $request->post('assignment_id', 0);
        if ($assignmentId <= 0) {
            return $this->redirect('/coaches/' . $id)->withError('بيانات غير صالحة');
        }

        CoachService::unassignFromAcademy($assignmentId);

        return $this->redirect('/coaches/' . $id)->withSuccess('تم إلغاء تعيين المدرب');
    }

    public function saveAvailability(Request $request, string $id): Response
    {
        $coach = Coach::find((int) $id);
        if (!$coach) {
            return $this->redirect('/coaches')->withError('المدرب غير موجود');
        }

        $slots = [];
        $days = $request->post('avail_day', []);
        $starts = $request->post('avail_start', []);
        $ends = $request->post('avail_end', []);

        if (is_array($days)) {
            for ($i = 0; $i < count($days); $i++) {
                if (isset($starts[$i], $ends[$i]) && $starts[$i] !== '' && $ends[$i] !== '') {
                    $slots[] = [
                        'day_of_week' => (int) $days[$i],
                        'start_time'  => $starts[$i],
                        'end_time'    => $ends[$i],
                    ];
                }
            }
        }

        CoachService::setAvailability((int) $id, $slots);

        return $this->redirect('/coaches/' . $id)->withSuccess('تم حفظ مواعيد المدرب');
    }

    private function handlePhotoUpload(Request $request): ?string
    {
        if (!isset($_FILES['photo']) || $_FILES['photo']['error'] !== UPLOAD_ERR_OK) {
            return null;
        }

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

        $allowedTypes = ['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, $allowedTypes, true)) {
            return null;
        }

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

        $dir = 'uploads/coaches';
        $fullDir = __DIR__ . '/../../../public/' . $dir;
        if (!is_dir($fullDir)) {
            mkdir($fullDir, 0755, true);
        }

        $filename = 'coach_' . time() . '_' . bin2hex(random_bytes(4)) . '.' . $ext;
        $dest = $fullDir . '/' . $filename;

        if (move_uploaded_file($file['tmp_name'], $dest)) {
            return '/' . $dir . '/' . $filename;
        }

        return null;
    }

    private static function getDayNames(): array
    {
        return [
            0 => 'الأحد',
            1 => 'الإثنين',
            2 => 'الثلاثاء',
            3 => 'الأربعاء',
            4 => 'الخميس',
            5 => 'الجمعة',
            6 => 'السبت',
        ];
    }
}
