<?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\Group;
use App\Modules\SportsActivity\Models\Program;
use App\Modules\SportsActivity\Services\EnrollmentService;
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', '')),
            '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['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 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, 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 {$where}
             ORDER BY g.name_ar ASC
             LIMIT {$perPage} OFFSET {$offset}",
            $params
        );

        $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,
            'programs'   => $programs,
            'coaches'    => $coaches,
        ]);
    }

    /**
     * Show create group form.
     */
    public function create(Request $request): Response
    {
        $db = App::getInstance()->db();
        $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', [
            '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);
        $minCapacity = (int) $request->post('min_capacity', 0);
        $maxCapacity = (int) $request->post('max_capacity', 0);
        $monthlyFeeMember = (float) $request->post('monthly_fee_member', 0);
        $monthlyFeeNonmember = (float) $request->post('monthly_fee_nonmember', 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
        if ($code !== '') {
            $db = App::getInstance()->db();
            $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');
        }

        $group = Group::create([
            'code'                   => $code,
            'name_ar'                => $nameAr,
            'name_en'                => $nameEn ?: null,
            'program_id'             => $programId,
            'coach_id'               => $coachId,
            'min_capacity'           => $minCapacity,
            'max_capacity'           => $maxCapacity,
            'current_count'          => 0,
            'is_full'                => 0,
            'monthly_fee_member'     => $monthlyFeeMember,
            'monthly_fee_nonmember'  => $monthlyFeeNonmember,
            'season_start'           => $seasonStart ?: null,
            'season_end'             => $seasonEnd ?: null,
            'status'                 => 'active',
        ]);

        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);

        // Available players for enrollment (not already in this group)
        $availablePlayers = $db->select(
            "SELECT p.id, p.full_name_ar as name_ar, p.registration_serial as code,
                    (SELECT COUNT(*) FROM sa_subscriptions s
                     WHERE s.player_id = p.id AND s.payment_status IN ('unpaid','overdue','partial')) as unpaid_count
             FROM sa_players p
             WHERE p.is_archived = 0 AND p.id NOT IN (
                SELECT player_id FROM sa_group_players WHERE group_id = ? AND status IN ('active','pending_payment')
             )
             ORDER BY p.full_name_ar ASC LIMIT 100",
            [(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",
            []
        );

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

    /**
     * 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();
        $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.edit', [
            'group'    => $group,
            'programs' => $programs,
            'coaches'  => $coaches,
        ]);
    }

    /**
     * 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);
        $minCapacity = (int) $request->post('min_capacity', 0);
        $maxCapacity = (int) $request->post('max_capacity', 0);
        $monthlyFeeMember = (float) $request->post('monthly_fee_member', 0);
        $monthlyFeeNonmember = (float) $request->post('monthly_fee_nonmember', 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)
        if ($code !== '') {
            $db = App::getInstance()->db();
            $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');
        }

        $group->update([
            'code'                   => $code,
            'name_ar'                => $nameAr,
            'name_en'                => $nameEn ?: null,
            'program_id'             => $programId,
            'coach_id'               => $coachId,
            'min_capacity'           => $minCapacity,
            'max_capacity'           => $maxCapacity,
            'monthly_fee_member'     => $monthlyFeeMember,
            'monthly_fee_nonmember'  => $monthlyFeeNonmember,
            'season_start'           => $seasonStart ?: null,
            'season_end'             => $seasonEnd ?: null,
        ]);

        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'] . ')';
            }
            return $this->redirect('/sa/groups/' . $id . '?enrollment_pending=1')->withSuccess($msg);
        }

        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]);
        }

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

    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']})");
    }
}
