<?php
declare(strict_types=1);

namespace App\Modules\SportsActivity\Services;

use App\Core\App;

final class PoolGridTemplateService
{
    public static function getTemplates(int $facilityId): array
    {
        $db = App::getInstance()->db();
        $templates = $db->select(
            "SELECT t.*,
                    (SELECT COUNT(*) FROM sa_pool_zone_template_entries WHERE template_id = t.id) as entries_count
             FROM sa_pool_zone_templates t
             WHERE t.facility_id = ? AND t.is_active = 1
             ORDER BY t.created_at DESC",
            [$facilityId]
        );
        return $templates;
    }

    public static function getTemplate(int $templateId): ?array
    {
        $db = App::getInstance()->db();
        $template = $db->selectOne("SELECT * FROM sa_pool_zone_templates WHERE id = ?", [$templateId]);
        if (!$template) return null;

        $template['entries'] = $db->select(
            "SELECT e.*, g.name_ar as group_name
             FROM sa_pool_zone_template_entries e
             LEFT JOIN sa_groups g ON g.id = e.group_id
             WHERE e.template_id = ?
             ORDER BY e.day_of_week, e.start_time",
            [$templateId]
        );

        return $template;
    }

    public static function createTemplate(int $facilityId, string $name, ?string $description, ?string $color, array $entries, string $recurrenceType = 'weekly', ?array $recurrenceConfig = null): array
    {
        $db = App::getInstance()->db();
        $ts = date('Y-m-d H:i:s');
        $employeeId = (int) (App::getInstance()->session()->get('employee_id') ?? 0);

        if (!trim($name)) {
            return ['success' => false, 'error' => 'اسم القالب مطلوب'];
        }

        if (empty($entries)) {
            return ['success' => false, 'error' => 'يجب إضافة إدخال واحد على الأقل'];
        }

        $validTypes = ['daily', 'weekly', 'biweekly', 'monthly', 'custom'];
        if (!in_array($recurrenceType, $validTypes, true)) {
            $recurrenceType = 'weekly';
        }

        $db->insert('sa_pool_zone_templates', [
            'facility_id'       => $facilityId,
            'name'              => trim($name),
            'description'       => $description ? trim($description) : null,
            'color'             => $color ?: '#3B82F6',
            'recurrence_type'   => $recurrenceType,
            'recurrence_config' => $recurrenceConfig ? json_encode($recurrenceConfig, JSON_UNESCAPED_UNICODE) : null,
            'is_active'         => 1,
            'created_by'        => $employeeId,
            'created_at'        => $ts,
            'updated_at'        => $ts,
        ]);

        $templateId = (int) $db->selectOne("SELECT LAST_INSERT_ID() as id", [])['id'];

        foreach ($entries as $entry) {
            $zoneJson = $entry['zone_selection_json'] ?? '{}';
            if (is_array($zoneJson)) {
                $zoneJson = json_encode($zoneJson, JSON_UNESCAPED_UNICODE);
            }

            $coachId = null;
            $groupId = !empty($entry['group_id']) ? (int) $entry['group_id'] : null;
            if ($groupId) {
                $group = $db->selectOne("SELECT coach_id FROM sa_groups WHERE id = ?", [$groupId]);
                $coachId = $group ? ((int) $group['coach_id'] ?: null) : null;
            }

            $db->insert('sa_pool_zone_template_entries', [
                'template_id'         => $templateId,
                'day_of_week'         => (int) ($entry['day_of_week'] ?? 0),
                'start_time'          => $entry['start_time'] ?? '09:00:00',
                'end_time'            => $entry['end_time'] ?? '10:00:00',
                'zone_selection_type' => $entry['zone_selection_type'] ?? 'all',
                'zone_selection_json' => $zoneJson,
                'assignment_type'     => $entry['assignment_type'] ?? 'training',
                'group_id'            => $groupId,
                'coach_id'            => $coachId,
                'label'               => $entry['label'] ?? $name,
                'notes'               => $entry['notes'] ?? null,
                'created_at'          => $ts,
                'updated_at'          => $ts,
            ]);
        }

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

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

        $template = $db->selectOne("SELECT id FROM sa_pool_zone_templates WHERE id = ?", [$templateId]);
        if (!$template) {
            return ['success' => false, 'error' => 'القالب غير موجود'];
        }

        $db->update('sa_pool_zone_templates', [
            'is_active'  => 0,
            'updated_at' => date('Y-m-d H:i:s'),
        ], 'id = ?', [$templateId]);

        return ['success' => true];
    }

    public static function expandTemplate(int $templateId, string $fromDate, string $toDate): array
    {
        $db = App::getInstance()->db();
        $ts = date('Y-m-d H:i:s');
        $employeeId = (int) (App::getInstance()->session()->get('employee_id') ?? 0);

        $template = self::getTemplate($templateId);
        if (!$template) {
            return ['success' => false, 'error' => 'القالب غير موجود'];
        }

        $facility = PoolGridService::getFacility((int) $template['facility_id']);
        if (!$facility) {
            return ['success' => false, 'error' => 'المرفق غير موجود'];
        }

        $maxRows = (int) ($facility['pool_grid_rows'] ?? 0);
        $maxCols = (int) ($facility['pool_grid_cols'] ?? 0);

        if ($maxRows < 1 || $maxCols < 1) {
            return ['success' => false, 'error' => 'الشبكة غير مهيأة'];
        }

        // Create run record
        $db->insert('sa_pool_zone_template_runs', [
            'template_id'     => $templateId,
            'date_from'       => $fromDate,
            'date_to'         => $toDate,
            'generated_count' => 0,
            'skipped_count'   => 0,
            'status'          => 'completed',
            'created_by'      => $employeeId,
            'created_at'      => $ts,
        ]);
        $runId = (int) $db->selectOne("SELECT LAST_INSERT_ID() as id", [])['id'];

        $entries = $template['entries'] ?? [];
        $recurrenceType = $template['recurrence_type'] ?? 'weekly';
        $generated = 0;
        $skipped = 0;

        // Iterate each day in range
        $current = strtotime($fromDate);
        $end = strtotime($toDate);
        $startTimestamp = strtotime($fromDate);

        while ($current <= $end) {
            $dayOfWeek = (int) date('w', $current); // 0=Sunday
            $dateStr = date('Y-m-d', $current);
            $dayOfMonth = (int) date('j', $current);
            $daysSinceStart = (int) (($current - $startTimestamp) / 86400);

            // Process matching entries for this day
            foreach ($entries as $entry) {
                $matches = false;
                switch ($recurrenceType) {
                    case 'daily':
                        $matches = true;
                        break;
                    case 'weekly':
                        $matches = ((int) $entry['day_of_week'] === $dayOfWeek);
                        break;
                    case 'biweekly':
                        $matches = ((int) $entry['day_of_week'] === $dayOfWeek) && (intdiv($daysSinceStart, 7) % 2 === 0);
                        break;
                    case 'monthly':
                        $monthDay = (int) ($entry['month_day'] ?? $entry['day_of_week']);
                        $matches = ($dayOfMonth === $monthDay);
                        break;
                    case 'custom':
                        $interval = (int) ($entry['day_interval'] ?? 1);
                        $matches = ($interval > 0 && $daysSinceStart % $interval === 0);
                        break;
                    default:
                        $matches = ((int) $entry['day_of_week'] === $dayOfWeek);
                }
                if (!$matches) continue;

                $cells = self::resolveZoneSelection(
                    $entry['zone_selection_type'],
                    $entry['zone_selection_json'],
                    $maxRows,
                    $maxCols
                );

                $startTime = $entry['start_time'];
                $endTime = $entry['end_time'];

                foreach ($cells as $cell) {
                    $row = (int) $cell['row'];
                    $col = (int) $cell['col'];

                    if ($row < 0 || $row >= $maxRows || $col < 0 || $col >= $maxCols) {
                        $skipped++;
                        continue;
                    }

                    $conflict = $db->selectOne(
                        "SELECT id FROM sa_pool_zone_bookings
                         WHERE facility_id = ? AND booking_date = ? AND start_time = ?
                         AND zone_row = ? AND zone_col = ? AND status = 'active'",
                        [(int) $template['facility_id'], $dateStr, $startTime, $row, $col]
                    );

                    if ($conflict) {
                        $skipped++;
                        continue;
                    }

                    $db->insert('sa_pool_zone_bookings', [
                        'facility_id'     => (int) $template['facility_id'],
                        'booking_date'    => $dateStr,
                        'start_time'      => $startTime,
                        'end_time'        => $endTime,
                        'zone_row'        => $row,
                        'zone_col'        => $col,
                        'assignment_type' => $entry['assignment_type'],
                        'group_id'        => $entry['group_id'] ? (int) $entry['group_id'] : null,
                        'coach_id'        => $entry['coach_id'] ? (int) $entry['coach_id'] : null,
                        'label'           => $entry['label'] ?: $template['name'],
                        'notes'           => $entry['notes'],
                        'template_run_id' => $runId,
                        'status'          => 'active',
                        'created_by'      => $employeeId,
                        'created_at'      => $ts,
                        'updated_at'      => $ts,
                    ]);
                    $generated++;
                }
            }

            $current = strtotime('+1 day', $current);
        }

        // Update run with counts
        $db->update('sa_pool_zone_template_runs', [
            'generated_count' => $generated,
            'skipped_count'   => $skipped,
        ], 'id = ?', [$runId]);

        return ['success' => true, 'generated' => $generated, 'skipped' => $skipped, 'run_id' => $runId];
    }

    public static function rollbackRun(int $runId): array
    {
        $db = App::getInstance()->db();
        $ts = date('Y-m-d H:i:s');
        $employeeId = (int) (App::getInstance()->session()->get('employee_id') ?? 0);

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

        if ($run['status'] === 'rolled_back') {
            return ['success' => false, 'error' => 'تم التراجع عن هذا التوسيع مسبقاً'];
        }

        // Cancel all bookings from this run
        $db->query(
            "UPDATE sa_pool_zone_bookings
             SET status = 'cancelled', cancelled_by = ?, cancelled_at = ?, updated_at = ?
             WHERE template_run_id = ? AND status = 'active'",
            [$employeeId, $ts, $ts, $runId]
        );

        $db->update('sa_pool_zone_template_runs', [
            'status'          => 'rolled_back',
            'rolled_back_at'  => $ts,
            'rolled_back_by'  => $employeeId,
        ], 'id = ?', [$runId]);

        return ['success' => true];
    }

    public static function getRunHistory(int $templateId): array
    {
        $db = App::getInstance()->db();
        return $db->select(
            "SELECT * FROM sa_pool_zone_template_runs WHERE template_id = ? ORDER BY created_at DESC LIMIT 20",
            [$templateId]
        );
    }

    private static function resolveZoneSelection(string $type, $json, int $maxRows, int $maxCols): array
    {
        $data = is_string($json) ? json_decode($json, true) : $json;
        if (!is_array($data)) $data = [];

        $cells = [];

        switch ($type) {
            case 'all':
                for ($r = 0; $r < $maxRows; $r++) {
                    for ($c = 0; $c < $maxCols; $c++) {
                        $cells[] = ['row' => $r, 'col' => $c];
                    }
                }
                break;

            case 'row':
                $rows = $data['rows'] ?? [];
                foreach ($rows as $r) {
                    $r = (int) $r;
                    if ($r >= 0 && $r < $maxRows) {
                        for ($c = 0; $c < $maxCols; $c++) {
                            $cells[] = ['row' => $r, 'col' => $c];
                        }
                    }
                }
                break;

            case 'column':
                $cols = $data['cols'] ?? [];
                foreach ($cols as $c) {
                    $c = (int) $c;
                    if ($c >= 0 && $c < $maxCols) {
                        for ($r = 0; $r < $maxRows; $r++) {
                            $cells[] = ['row' => $r, 'col' => $c];
                        }
                    }
                }
                break;

            case 'cells':
            default:
                if (isset($data[0]) && is_array($data[0])) {
                    foreach ($data as $cell) {
                        if (isset($cell['row']) && isset($cell['col'])) {
                            $cells[] = ['row' => (int) $cell['row'], 'col' => (int) $cell['col']];
                        }
                    }
                }
                break;
        }

        return $cells;
    }
}
