<?php
declare(strict_types=1);

namespace App\Modules\SportsActivity\Controllers;

use App\Core\Controller;
use App\Core\Request;
use App\Core\Response;
use App\Core\App;
use App\Core\Pagination;
use App\Modules\SportsActivity\Models\Discipline;
use App\Modules\SportsActivity\Models\Group;
use App\Modules\SportsActivity\Models\Program;
use App\Modules\SportsActivity\Services\EnrollmentService;
use App\Modules\SportsActivity\Services\GroupTransferService;
use App\Modules\SportsActivity\Services\ScheduleGeneratorService;

class GroupController extends Controller
{
    /**
     * List groups with search, filter by program/coach, pagination.
     */
    public function index(Request $request): Response
    {
        $filters = [
            'q'             => trim((string) $request->get('q', '')),
            'discipline_id' => trim((string) $request->get('discipline_id', '')),
            'program_id'    => trim((string) $request->get('program_id', '')),
            'coach_id'      => trim((string) $request->get('coach_id', '')),
        ];

        $page = max(1, (int) $request->get('page', 1));
        $perPage = 25;
        $db = App::getInstance()->db();

        $where = "g.is_archived = 0";
        $params = [];

        if ($filters['q'] !== '') {
            $where .= " AND (g.name_ar LIKE ? OR g.code LIKE ?)";
            $params[] = '%' . $filters['q'] . '%';
            $params[] = '%' . $filters['q'] . '%';
        }

        if ($filters['discipline_id'] !== '') {
            $where .= " AND p.discipline_id = ?";
            $params[] = (int) $filters['discipline_id'];
        }

        if ($filters['program_id'] !== '') {
            $where .= " AND g.program_id = ?";
            $params[] = (int) $filters['program_id'];
        }

        if ($filters['coach_id'] !== '') {
            $where .= " AND g.coach_id = ?";
            $params[] = (int) $filters['coach_id'];
        }

        $total = (int) ($db->selectOne(
            "SELECT COUNT(*) as cnt FROM sa_groups g LEFT JOIN sa_programs p ON p.id = g.program_id WHERE {$where}",
            $params
        )['cnt'] ?? 0);
        $pagination = Pagination::paginate($total, $perPage, $page);

        $offset = ($page - 1) * $perPage;
        $groups = $db->select(
            "SELECT g.*, p.name_ar as program_name, p.monthly_fee_member as program_fee, c.full_name_ar as coach_name,
                    EXISTS(SELECT 1 FROM sa_group_schedule gs WHERE gs.group_id = g.id AND gs.is_active = 1) as has_schedule
             FROM sa_groups g
             LEFT JOIN sa_programs p ON p.id = g.program_id
             LEFT JOIN sa_coaches c ON c.id = g.coach_id
             WHERE {$where}
             ORDER BY g.name_ar ASC
             LIMIT {$perPage} OFFSET {$offset}",
            $params
        );

        $disciplines = Discipline::getActive();
        $programs = Program::getActive();
        $coaches = $db->select("SELECT id, full_name_ar as name_ar FROM sa_coaches WHERE is_archived = 0 ORDER BY full_name_ar", []);

        return $this->view('SportsActivity.Views.groups.index', [
            'groups'      => $groups,
            'pagination'  => $pagination,
            'filters'     => $filters,
            'disciplines' => $disciplines,
            'programs'    => $programs,
            'coaches'     => $coaches,
        ]);
    }

    /**
     * Show create group form.
     */
    public function create(Request $request): Response
    {
        $db = App::getInstance()->db();
        $disciplines = Discipline::getActive();
        $programs = Program::getActive();
        $coaches = $db->select("SELECT id, full_name_ar as name_ar FROM sa_coaches WHERE is_archived = 0 ORDER BY full_name_ar", []);

        return $this->view('SportsActivity.Views.groups.create', [
            'disciplines' => $disciplines,
            'programs'    => $programs,
            'coaches'     => $coaches,
        ]);
    }

    /**
     * Validate and store a new group.
     */
    public function store(Request $request): Response
    {
        $code = strtoupper(trim((string) $request->post('code', '')));
        $nameAr = trim((string) $request->post('name_ar', ''));
        $nameEn = trim((string) $request->post('name_en', ''));
        $programId = (int) $request->post('program_id', 0);
        $coachId = (int) $request->post('coach_id', 0);
        $seasonStart = trim((string) $request->post('season_start', ''));
        $seasonEnd = trim((string) $request->post('season_end', ''));

        $errors = [];
        if ($code === '') {
            $errors[] = 'كود المجموعة مطلوب';
        }
        if ($nameAr === '' || mb_strlen($nameAr) < 2) {
            $errors[] = 'اسم المجموعة بالعربي مطلوب (حرفان على الأقل)';
        }
        if ($programId === 0) {
            $errors[] = 'البرنامج مطلوب';
        }
        if ($coachId === 0) {
            $errors[] = 'المدرب مطلوب';
        }

        if ($seasonStart !== '' && $seasonEnd !== '' && $seasonStart >= $seasonEnd) {
            $errors[] = 'تاريخ بداية الموسم يجب أن يكون قبل تاريخ النهاية';
        }

        // Check unique code
        $db = App::getInstance()->db();
        if ($code !== '') {
            $existing = $db->selectOne("SELECT id FROM sa_groups WHERE code = ?", [$code]);
            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('/sa/groups/create');
        }

        // Inherit capacity from program
        $programData = $db->selectOne("SELECT max_capacity, min_capacity FROM sa_programs WHERE id = ?", [$programId]);

        $group = Group::create([
            'code'          => $code,
            'name_ar'       => $nameAr,
            'name_en'       => $nameEn ?: null,
            'program_id'    => $programId,
            'coach_id'      => $coachId,
            'min_capacity'  => (int) ($programData['min_capacity'] ?? 1),
            'max_capacity'  => (int) ($programData['max_capacity'] ?? 20),
            'current_count' => 0,
            'is_full'       => 0,
            'season_start'  => $seasonStart ?: null,
            'season_end'    => $seasonEnd ?: null,
            'status'        => 'active',
        ]);

        // Save coaches to pivot table
        $this->syncGroupCoaches($db, (int) $group->id, $coachId, $request->post('additional_coaches', []));

        return $this->redirect('/sa/groups/' . $group->id)->withSuccess('تم إضافة المجموعة بنجاح');
    }

    /**
     * Show group detail with players and schedule.
     */
    public function show(Request $request, string $id): Response
    {
        $db = App::getInstance()->db();
        $group = $db->selectOne(
            "SELECT g.*, p.name_ar as program_name, c.full_name_ar as coach_name
             FROM sa_groups g
             LEFT JOIN sa_programs p ON p.id = g.program_id
             LEFT JOIN sa_coaches c ON c.id = g.coach_id
             WHERE g.id = ? AND g.is_archived = 0",
            [(int) $id]
        );

        if (!$group) {
            return $this->redirect('/sa/groups')->withError('المجموعة غير موجودة');
        }

        $players = Group::getPlayers((int) $id);
        $schedule = Group::getSchedule((int) $id);

        // Facility units for schedule
        $facilityUnits = $db->select(
            "SELECT fu.id, fu.name_ar, fu.code, f.name_ar as facility_name
             FROM sa_facility_units fu
             JOIN sa_facilities f ON f.id = fu.facility_id
             WHERE fu.is_active = 1
             ORDER BY f.name_ar ASC, fu.name_ar ASC",
            []
        );

        // Additional coaches from pivot
        $additionalCoaches = $db->select(
            "SELECT c.id, c.full_name_ar FROM sa_group_coaches gc JOIN sa_coaches c ON c.id = gc.coach_id WHERE gc.group_id = ? AND gc.role != 'primary' ORDER BY c.full_name_ar",
            [(int) $id]
        );

        return $this->view('SportsActivity.Views.groups.show', [
            'group'            => $group,
            'players'          => $players,
            'schedule'         => $schedule,
            'facilityUnits'    => $facilityUnits,
            'statuses'         => Group::getStatusOptions(),
            'additionalCoaches' => $additionalCoaches,
        ]);
    }

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

        $db = App::getInstance()->db();
        $disciplines = Discipline::getActive();
        $programs = Program::getActive();
        $coaches = $db->select("SELECT id, full_name_ar as name_ar FROM sa_coaches WHERE is_archived = 0 ORDER BY full_name_ar", []);

        $disciplineId = $db->selectOne(
            "SELECT discipline_id FROM sa_programs WHERE id = ?",
            [(int) $group->program_id]
        );

        $groupCoachIds = array_column(
            $db->select("SELECT coach_id FROM sa_group_coaches WHERE group_id = ? AND role != 'primary'", [(int) $id]),
            'coach_id'
        );

        return $this->view('SportsActivity.Views.groups.edit', [
            'group'         => $group,
            'disciplines'   => $disciplines,
            'programs'      => $programs,
            'coaches'       => $coaches,
            'disciplineId'  => $disciplineId ? (int) $disciplineId['discipline_id'] : null,
            'groupCoachIds' => $groupCoachIds,
        ]);
    }

    /**
     * Validate and update an existing group.
     */
    public function update(Request $request, string $id): Response
    {
        $group = Group::find((int) $id);
        if (!$group) {
            return $this->redirect('/sa/groups')->withError('المجموعة غير موجودة');
        }

        $code = strtoupper(trim((string) $request->post('code', '')));
        $nameAr = trim((string) $request->post('name_ar', ''));
        $nameEn = trim((string) $request->post('name_en', ''));
        $programId = (int) $request->post('program_id', 0);
        $coachId = (int) $request->post('coach_id', 0);
        $seasonStart = trim((string) $request->post('season_start', ''));
        $seasonEnd = trim((string) $request->post('season_end', ''));

        $errors = [];
        if ($code === '') {
            $errors[] = 'كود المجموعة مطلوب';
        }
        if ($nameAr === '' || mb_strlen($nameAr) < 2) {
            $errors[] = 'اسم المجموعة بالعربي مطلوب (حرفان على الأقل)';
        }
        if ($programId === 0) {
            $errors[] = 'البرنامج مطلوب';
        }
        if ($coachId === 0) {
            $errors[] = 'المدرب مطلوب';
        }

        if ($seasonStart !== '' && $seasonEnd !== '' && $seasonStart >= $seasonEnd) {
            $errors[] = 'تاريخ بداية الموسم يجب أن يكون قبل تاريخ النهاية';
        }

        // Check unique code (exclude current)
        $db = App::getInstance()->db();
        if ($code !== '') {
            $existing = $db->selectOne("SELECT id FROM sa_groups WHERE code = ? AND id != ?", [$code, (int) $id]);
            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('/sa/groups/' . $id . '/edit');
        }

        // Inherit capacity from program
        $programData = $db->selectOne("SELECT max_capacity, min_capacity FROM sa_programs WHERE id = ?", [$programId]);

        $group->update([
            'code'         => $code,
            'name_ar'      => $nameAr,
            'name_en'      => $nameEn ?: null,
            'program_id'   => $programId,
            'coach_id'     => $coachId,
            'min_capacity' => (int) ($programData['min_capacity'] ?? 1),
            'max_capacity' => (int) ($programData['max_capacity'] ?? 20),
            'season_start' => $seasonStart ?: null,
            'season_end'   => $seasonEnd ?: null,
        ]);

        // Sync coaches pivot table
        $this->syncGroupCoaches($db, (int) $id, $coachId, $request->post('additional_coaches', []));

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

    /**
     * Enroll a player in this group.
     */
    public function enroll(Request $request, string $id): Response
    {
        $playerId = (int) $request->post('player_id', 0);
        if ($playerId === 0) {
            return $this->redirect('/sa/groups/' . $id)->withError('يرجى اختيار لاعب');
        }

        $result = EnrollmentService::enroll((int) $id, $playerId);

        if ($result['success']) {
            $msg = 'تم تسجيل اللاعب — في انتظار الدفع';
            if (!empty($result['request_number'])) {
                $msg .= ' (طلب دفع: ' . $result['request_number'] . ')';
            }
            $redirect = $this->redirect('/sa/groups/' . $id . '?enrollment_pending=1')->withSuccess($msg);
            if (!empty($result['medical_warning'])) {
                $session = App::getInstance()->session();
                $alerts = $session->get('_alerts', []);
                $alerts[] = ['type' => 'warning', 'message' => $result['medical_warning']];
                $session->flash('_alerts', $alerts);
            }
            return $redirect;
        }

        return $this->redirect('/sa/groups/' . $id)->withError($result['error']);
    }

    /**
     * Remove (withdraw) a player from this group.
     */
    public function removePlayer(Request $request, string $id): Response
    {
        $playerId = (int) $request->post('player_id', 0);
        if ($playerId === 0) {
            return $this->redirect('/sa/groups/' . $id)->withError('يرجى تحديد اللاعب');
        }

        $reason = trim((string) $request->post('reason', ''));
        $result = EnrollmentService::withdraw((int) $id, $playerId, $reason);

        if ($result['success']) {
            return $this->redirect('/sa/groups/' . $id)->withSuccess('تم سحب اللاعب من المجموعة');
        }

        return $this->redirect('/sa/groups/' . $id)->withError($result['error']);
    }

    /**
     * Save/update group schedule entries.
     */
    public function saveSchedule(Request $request, string $id): Response
    {
        $db = App::getInstance()->db();

        $group = Group::find((int) $id);
        if (!$group) {
            return $this->redirect('/sa/groups')->withError('المجموعة غير موجودة');
        }

        $facilityUnitIds = $request->post('facility_unit_id', []);
        $daysOfWeek = $request->post('day_of_week', []);
        $startTimes = $request->post('start_time', []);
        $endTimes = $request->post('end_time', []);

        if (!is_array($facilityUnitIds)) {
            $facilityUnitIds = [];
        }

        // Insert or reactivate new schedule entries
        $count = min(count($facilityUnitIds), count($daysOfWeek), count($startTimes), count($endTimes));
        $inserted = 0;
        $keepIds = [];

        for ($i = 0; $i < $count; $i++) {
            $unitId = (int) ($facilityUnitIds[$i] ?? 0);
            $day = (int) ($daysOfWeek[$i] ?? 0);
            $start = trim((string) ($startTimes[$i] ?? ''));
            $end = trim((string) ($endTimes[$i] ?? ''));

            if ($unitId === 0 || $start === '' || $end === '') {
                continue;
            }

            $existing = $db->selectOne(
                "SELECT id FROM sa_group_schedule WHERE group_id = ? AND facility_unit_id = ? AND day_of_week = ? AND start_time = ?",
                [(int) $id, $unitId, $day, $start]
            );

            if ($existing) {
                $db->update('sa_group_schedule', [
                    'end_time'   => $end,
                    'is_active'  => 1,
                    'updated_at' => date('Y-m-d H:i:s'),
                ], 'id = ?', [(int) $existing['id']]);
                $keepIds[] = (int) $existing['id'];
                $inserted++;
            } else {
                $newId = $db->insert('sa_group_schedule', [
                    'group_id'         => (int) $id,
                    'facility_unit_id' => $unitId,
                    'day_of_week'      => $day,
                    'start_time'       => $start,
                    'end_time'         => $end,
                    'is_active'        => 1,
                    'created_at'       => date('Y-m-d H:i:s'),
                    'updated_at'       => date('Y-m-d H:i:s'),
                ]);
                $keepIds[] = $newId;
                $inserted++;
            }
        }

        // Deactivate only schedules not in the new set
        if (!empty($keepIds)) {
            $placeholders = implode(',', array_fill(0, count($keepIds), '?'));
            $db->query(
                "UPDATE sa_group_schedule SET is_active = 0, updated_at = NOW() WHERE group_id = ? AND is_active = 1 AND id NOT IN ({$placeholders})",
                array_merge([(int) $id], $keepIds)
            );
        } else {
            $db->update('sa_group_schedule', [
                'is_active'  => 0,
                'updated_at' => date('Y-m-d H:i:s'),
            ], 'group_id = ? AND is_active = 1', [(int) $id]);
        }

        // Auto-generate training sessions for next 4 weeks
        if ($inserted > 0) {
            $fromDate = date('Y-m-d');
            $toDate = date('Y-m-d', strtotime('+4 weeks'));
            ScheduleGeneratorService::generateForGroup((int) $id, $fromDate, $toDate);
        }

        return $this->redirect('/sa/groups/' . $id)->withSuccess("تم حفظ الجدول ({$inserted} حصة)");
    }

    public function forceEnroll(Request $request, string $id): Response
    {
        $this->authorize('sa.group.force_enroll');

        $playerId = (int) $request->post('player_id', 0);
        if ($playerId === 0) {
            return $this->redirect('/sa/groups/' . $id)->withError('يرجى اختيار لاعب');
        }

        $result = EnrollmentService::forceEnroll((int) $id, $playerId);

        if ($result['success']) {
            $msg = 'تم تسجيل اللاعب (تجاوز السعة) — في انتظار الدفع';
            if (!empty($result['request_number'])) {
                $msg .= ' (طلب دفع: ' . $result['request_number'] . ')';
            }
            return $this->redirect('/sa/groups/' . $id)->withSuccess($msg);
        }

        return $this->redirect('/sa/groups/' . $id)->withError($result['error']);
    }

    public function transferPlayer(Request $request, string $id): Response
    {
        $playerId = (int) $request->post('player_id', 0);
        $toGroupId = (int) $request->post('to_group_id', 0);
        $reason = trim((string) $request->post('reason', ''));
        $force = (bool) $request->post('force', false);

        if ($playerId === 0 || $toGroupId === 0) {
            return $this->redirect('/sa/groups/' . $id)->withError('يرجى تحديد اللاعب والمجموعة المنقول إليها');
        }

        $result = GroupTransferService::transfer($playerId, (int) $id, $toGroupId, $reason, $force);

        if ($result['success']) {
            return $this->redirect('/sa/groups/' . $id)->withSuccess('تم نقل اللاعب بنجاح');
        }

        return $this->redirect('/sa/groups/' . $id)->withError($result['error']);
    }

    private function syncGroupCoaches(\App\Core\Database $db, int $groupId, int $primaryCoachId, mixed $additionalCoachIds): void
    {
        if (!is_array($additionalCoachIds)) {
            $additionalCoachIds = [];
        }
        $additionalCoachIds = array_map('intval', $additionalCoachIds);
        $additionalCoachIds = array_filter($additionalCoachIds, fn(int $id) => $id > 0 && $id !== $primaryCoachId);

        $db->delete('sa_group_coaches', 'group_id = ?', [$groupId]);

        $db->insert('sa_group_coaches', [
            'group_id'   => $groupId,
            'coach_id'   => $primaryCoachId,
            'role'       => 'primary',
            'created_at' => date('Y-m-d H:i:s'),
        ]);

        foreach ($additionalCoachIds as $coachId) {
            $db->insert('sa_group_coaches', [
                'group_id'   => $groupId,
                'coach_id'   => $coachId,
                'role'       => 'assistant',
                'created_at' => date('Y-m-d H:i:s'),
            ]);
        }
    }

    public function generateSessions(Request $request, string $id): Response
    {
        $group = Group::find((int) $id);
        if (!$group) {
            return $this->redirect('/sa/groups')->withError('المجموعة غير موجودة');
        }

        $fromDate = trim((string) $request->post('from_date', ''));
        $toDate = trim((string) $request->post('to_date', ''));

        if ($fromDate === '' || $toDate === '') {
            return $this->redirect('/sa/groups/' . $id)->withError('يجب تحديد تاريخ البداية والنهاية');
        }

        if ($fromDate >= $toDate) {
            return $this->redirect('/sa/groups/' . $id)->withError('تاريخ البداية يجب أن يكون قبل تاريخ النهاية');
        }

        $result = ScheduleGeneratorService::generateForGroup((int) $id, $fromDate, $toDate);

        if (!$result['success']) {
            return $this->redirect('/sa/groups/' . $id)->withError($result['error']);
        }

        return $this->redirect('/sa/groups/' . $id)->withSuccess("تم توليد {$result['generated']} حصة تدريبية (تم تخطي {$result['skipped']})");
    }
}
