<?php
declare(strict_types=1);

namespace App\Modules\Scheduling\Services;

use App\Core\App;
use App\Modules\Scheduling\Models\SchedulingRule;

class ConflictDetectionService
{
    public static function detectConflicts(array $proposedSession): array
    {
        $conflicts = [];

        $conflicts = array_merge($conflicts, self::checkCoachOverlap($proposedSession));
        $conflicts = array_merge($conflicts, self::checkFacilityOverlap($proposedSession));
        $conflicts = array_merge($conflicts, self::checkPlayerOverlap($proposedSession));
        $conflicts = array_merge($conflicts, self::checkRuleViolations($proposedSession));

        return $conflicts;
    }

    public static function checkCoachOverlap(array $session): array
    {
        if (empty($session['coach_id']) || empty($session['date']) || empty($session['start_time']) || empty($session['end_time'])) {
            return [];
        }

        $db = App::getInstance()->db();
        $overlaps = $db->select(
            "SELECT ts.*, tg.name_ar AS group_name
             FROM training_sessions ts
             LEFT JOIN training_groups tg ON tg.id = ts.group_id
             WHERE ts.coach_id = ? AND ts.session_date = ? AND ts.status NOT IN ('cancelled')
             AND ((ts.start_time < ? AND ts.end_time > ?) OR (ts.start_time < ? AND ts.end_time > ?) OR (ts.start_time >= ? AND ts.end_time <= ?))
             AND ts.id != ?",
            [
                (int) $session['coach_id'],
                $session['date'],
                $session['end_time'], $session['start_time'],
                $session['end_time'], $session['start_time'],
                $session['start_time'], $session['end_time'],
                (int) ($session['exclude_session_id'] ?? 0),
            ]
        );

        $conflicts = [];
        foreach ($overlaps as $o) {
            $conflicts[] = [
                'type'        => 'coach_overlap',
                'severity'    => 'error',
                'description' => 'المدرب لديه جلسة أخرى: ' . ($o['group_name'] ?? '') . ' (' . substr($o['start_time'], 0, 5) . '-' . substr($o['end_time'], 0, 5) . ')',
                'entity_a'    => ['type' => 'session', 'id' => (int) ($session['session_id'] ?? 0)],
                'entity_b'    => ['type' => 'session', 'id' => (int) $o['id']],
            ];
        }

        return $conflicts;
    }

    public static function checkFacilityOverlap(array $session): array
    {
        if (empty($session['facility_id']) || empty($session['date']) || empty($session['start_time']) || empty($session['end_time'])) {
            return [];
        }

        $db = App::getInstance()->db();

        $rules = SchedulingRule::getActiveRules('facility_buffer', (int) $session['facility_id']);
        $bufferMinutes = 0;
        foreach ($rules as $rule) {
            $config = json_decode($rule['config_json'] ?? '{}', true);
            $bufferMinutes = max($bufferMinutes, (int) ($config['buffer_minutes'] ?? 0));
        }

        $adjustedStart = date('H:i:s', strtotime($session['start_time']) - ($bufferMinutes * 60));
        $adjustedEnd = date('H:i:s', strtotime($session['end_time']) + ($bufferMinutes * 60));

        $overlaps = $db->select(
            "SELECT * FROM reservations
             WHERE facility_id = ? AND reservation_date = ? AND status NOT IN ('cancelled')
             AND ((start_time < ? AND end_time > ?) OR (start_time < ? AND end_time > ?))
             AND id != ?",
            [
                (int) $session['facility_id'],
                $session['date'],
                $adjustedEnd, $adjustedStart,
                $adjustedEnd, $adjustedStart,
                (int) ($session['exclude_reservation_id'] ?? 0),
            ]
        );

        $conflicts = [];
        foreach ($overlaps as $o) {
            $conflicts[] = [
                'type'        => 'facility_overlap',
                'severity'    => 'error',
                'description' => 'المرفق محجوز: ' . substr($o['start_time'], 0, 5) . '-' . substr($o['end_time'], 0, 5) . ' (' . ($o['booker_name'] ?? '') . ')',
                'entity_a'    => ['type' => 'reservation', 'id' => (int) ($session['reservation_id'] ?? 0)],
                'entity_b'    => ['type' => 'reservation', 'id' => (int) $o['id']],
            ];
        }

        return $conflicts;
    }

    public static function checkPlayerOverlap(array $session): array
    {
        if (empty($session['player_ids']) || empty($session['date']) || empty($session['start_time']) || empty($session['end_time'])) {
            return [];
        }

        $db = App::getInstance()->db();
        $conflicts = [];

        $placeholders = implode(',', array_fill(0, count($session['player_ids']), '?'));
        $params = array_merge(
            $session['player_ids'],
            [$session['date'], $session['end_time'], $session['start_time']]
        );

        $overlaps = $db->select(
            "SELECT sa.player_id, ts.session_date, ts.start_time, ts.end_time, tg.name_ar
             FROM session_attendance sa
             JOIN training_sessions ts ON ts.id = sa.session_id
             LEFT JOIN training_groups tg ON tg.id = ts.group_id
             WHERE sa.player_id IN ({$placeholders})
             AND ts.session_date = ? AND ts.status NOT IN ('cancelled')
             AND (ts.start_time < ? AND ts.end_time > ?)",
            $params
        );

        foreach ($overlaps as $o) {
            $conflicts[] = [
                'type'        => 'player_overlap',
                'severity'    => 'warning',
                'description' => 'لاعب #' . $o['player_id'] . ' لديه جلسة أخرى: ' . ($o['name_ar'] ?? '') . ' (' . substr($o['start_time'], 0, 5) . ')',
                'entity_a'    => ['type' => 'player', 'id' => (int) $o['player_id']],
            ];
        }

        return $conflicts;
    }

    public static function checkRuleViolations(array $session): array
    {
        $conflicts = [];
        $db = App::getInstance()->db();

        if (!empty($session['coach_id']) && !empty($session['date'])) {
            $rules = SchedulingRule::getActiveRules('coach_max_hours');
            foreach ($rules as $rule) {
                $config = json_decode($rule['config_json'] ?? '{}', true);
                $maxHours = (int) ($config['max_hours'] ?? 8);

                $totalHours = $db->selectOne(
                    "SELECT COALESCE(SUM(TIMESTAMPDIFF(MINUTE, start_time, end_time)), 0) / 60 AS hrs
                     FROM training_sessions WHERE coach_id = ? AND session_date = ? AND status NOT IN ('cancelled')",
                    [(int) $session['coach_id'], $session['date']]
                );

                $proposedHours = (strtotime($session['end_time']) - strtotime($session['start_time'])) / 3600;
                if (((float) ($totalHours['hrs'] ?? 0) + $proposedHours) > $maxHours) {
                    $conflicts[] = [
                        'type'        => 'rule_violation',
                        'severity'    => 'warning',
                        'description' => 'المدرب سيتجاوز الحد الأقصى (' . $maxHours . ' ساعة/يوم)',
                    ];
                }
            }
        }

        return $conflicts;
    }

    public static function suggestAlternatives(array $proposedSession, int $limit = 5): array
    {
        $db = App::getInstance()->db();
        $suggestions = [];

        $currentDate = $proposedSession['date'] ?? date('Y-m-d');
        $duration = (strtotime($proposedSession['end_time'] ?? '08:00') - strtotime($proposedSession['start_time'] ?? '07:00')) / 60;

        for ($dayOffset = 0; $dayOffset <= 7 && count($suggestions) < $limit; $dayOffset++) {
            $checkDate = date('Y-m-d', strtotime($currentDate . " +{$dayOffset} days"));
            $dayOfWeek = (int) date('w', strtotime($checkDate));
            if ($dayOfWeek === 5) continue; // Skip Friday

            for ($hour = 6; $hour <= 21 && count($suggestions) < $limit; $hour++) {
                $startTime = sprintf('%02d:00:00', $hour);
                $endTime = date('H:i:s', strtotime($startTime) + ($duration * 60));

                if ($checkDate === $currentDate && $startTime === ($proposedSession['start_time'] ?? '')) continue;

                $alt = array_merge($proposedSession, [
                    'date'       => $checkDate,
                    'start_time' => $startTime,
                    'end_time'   => $endTime,
                ]);

                $altConflicts = self::detectConflicts($alt);
                $errors = array_filter($altConflicts, fn($c) => $c['severity'] === 'error');

                if (empty($errors)) {
                    $suggestions[] = [
                        'date'       => $checkDate,
                        'start_time' => $startTime,
                        'end_time'   => $endTime,
                        'day_name'   => ['الأحد','الإثنين','الثلاثاء','الأربعاء','الخميس','الجمعة','السبت'][$dayOfWeek],
                        'warnings'   => count($altConflicts),
                    ];
                }
            }
        }

        return $suggestions;
    }

    public static function logConflict(array $conflict, string $date): void
    {
        $db = App::getInstance()->db();
        $db->insert('scheduling_conflicts', [
            'conflict_type'      => $conflict['type'] ?? 'unknown',
            'severity'           => $conflict['severity'] ?? 'warning',
            'entity_a_type'      => $conflict['entity_a']['type'] ?? '',
            'entity_a_id'        => (int) ($conflict['entity_a']['id'] ?? 0),
            'entity_b_type'      => $conflict['entity_b']['type'] ?? null,
            'entity_b_id'        => $conflict['entity_b']['id'] ?? null,
            'conflict_date'      => $date,
            'conflict_time_start'=> $conflict['start_time'] ?? '00:00:00',
            'conflict_time_end'  => $conflict['end_time'] ?? '23:59:59',
            'description_ar'     => $conflict['description'] ?? '',
            'resolution'         => 'pending',
            'detected_at'        => date('Y-m-d H:i:s'),
            'created_at'         => date('Y-m-d H:i:s'),
        ]);
    }
}
