<?php

namespace App\Commands;

use CodeIgniter\CLI\BaseCommand;
use CodeIgniter\CLI\CLI;

class CheckSchedule extends BaseCommand
{
    /**
     * The Command's Group
     *
     * @var string
     */
    protected $group = 'App';

    /**
     * The Command's Name
     *
     * @var string
     */
    protected $name = 'app:check-schedule';
    protected $description = 'Analyze database schedule loads and constraints';

    public function run(array $params)
    {
        $db = \Config\Database::connect();
        
        // 1. Get draft/latest schedules
        $schedules = $db->table('schedules')->get()->getResultArray();
        if (empty($schedules)) {
            CLI::error('No schedules found in the database!');
            return;
        }

        foreach ($schedules as $s) {
            CLI::write("==================================================", 'light_blue');
            CLI::write("Schedule: " . $s['name'] . " (ID: " . $s['id'] . ")", 'yellow');
            CLI::write("Status: " . $s['status']);
            CLI::write("Active Days: " . $s['active_days']);
            
            $activeDays = explode(',', $s['active_days']);
            $yearId = $s['academic_year_id'];
            $periodId = $s['academic_period_id'];
            
            // 2. Count active classrooms
            $classrooms = $db->table('classrooms')->get()->getResultArray();
            $classroomCount = count($classrooms);
            CLI::write("Total Classrooms: " . $classroomCount);

            // 3. Count KBM timeslots per active day
            $timeslots = $db->table('schedule_timeslots')
                ->whereIn('day', $activeDays)
                ->where('slot_type', 'kbm')
                ->where('is_active', 1)
                ->orderBy('day')
                ->get()->getResultArray();
            
            $slotsByDay = [];
            foreach ($timeslots as $t) {
                $d = $t['day'];
                $slotsByDay[$d] = ($slotsByDay[$d] ?? 0) + 1;
            }
            
            $totalSlotsPerClassroom = count($timeslots);
            $totalAvailableSlots = $totalSlotsPerClassroom * $classroomCount;
            
            CLI::write("KBM Slots available per Classroom: " . $totalSlotsPerClassroom);
            CLI::write("KBM Slots by Day:");
            foreach ($slotsByDay as $day => $count) {
                CLI::write("  - Day $day: $count slots");
            }
            CLI::write("Total Capacity (Classroom KBM Slots): " . $totalAvailableSlots);

            // 4. Sum load hours
            $loads = $db->table('schedule_loads')
                ->where('academic_year_id', $yearId)
                ->where('academic_period_id', $periodId)
                ->get()->getResultArray();
            
            $totalRequestedHours = 0;
            $classroomLoads = [];
            $splitConfigsCount = [];
            $unsplitCount = 0;
            
            foreach ($loads as $l) {
                $totalRequestedHours += (int)$l['hours_per_week'];
                $cId = $l['classroom_id'];
                $classroomLoads[$cId] = ($classroomLoads[$cId] ?? 0) + (int)$l['hours_per_week'];
                
                $cfg = trim($l['split_config'] ?? '');
                if ($cfg === '') {
                    $unsplitCount++;
                } else {
                    $splitConfigsCount[$cfg] = ($splitConfigsCount[$cfg] ?? 0) + 1;
                }
            }
            
            CLI::write("Total Requested Load Hours: " . $totalRequestedHours, $totalRequestedHours > $totalAvailableSlots ? 'red' : 'green');
            CLI::write("Unsplit loads (default to single block): " . $unsplitCount);
            CLI::write("Split configurations distribution:");
            foreach ($splitConfigsCount as $cfg => $count) {
                CLI::write("  - '$cfg': $count loads");
            }
            
            CLI::write("\n--- Classroom Load Analysis ---", 'cyan');
            foreach ($classrooms as $c) {
                $cId = $c['id'];
                $loadHours = $classroomLoads[$cId] ?? 0;
                CLI::write("Classroom: " . $c['name'] . " (ID: $cId) - Requested: $loadHours hours");
                if ($loadHours > $totalSlotsPerClassroom) {
                    CLI::error("  - OVERLIMIT: Classroom load ($loadHours) exceeds timeslot capacity ($totalSlotsPerClassroom)!");
                }
            }
            
            if ($totalRequestedHours > $totalAvailableSlots) {
                CLI::error("OVERCAPACITY: Requested load hours exceed total classroom slots capacity!");
            }
        }
            
        // Run the generator for schedule ID 7
        CLI::write("\n==================================================", 'light_blue');
        CLI::write("Running generator for Schedule ID 7...", 'yellow');
        
        $generator = new \App\Services\ScheduleGeneratorService();
        $schedule = $db->table('schedules')->where('id', 7)->get()->getRowArray();
        
        if (!$schedule) {
            CLI::error("Schedule ID 7 not found!");
            return;
        }
        
        $result = $generator->generate(
            scheduleId: 7,
            yearId: (int)$schedule['academic_year_id'],
            periodId: (int)$schedule['academic_period_id'],
            activeDays: $schedule['active_days'],
            keepManual: false
        );
        
        CLI::write("\n--- Generator Results ---", 'cyan');
        CLI::write("Placed: " . $result['placed'] . " / " . $result['total'] . " hours (" . round($result['placed'] / $result['total'] * 100, 2) . "%)");
        CLI::write("Conflicts Count: " . count($result['conflicts']));
        
        // Count classroom clashes from DB
        $classClashes = $db->table('schedule_entries')
            ->select('classroom_id, day, slot_number, COUNT(*) as cnt')
            ->where('schedule_id', 7)
            ->groupBy('classroom_id, day, slot_number')
            ->having('cnt > 1')
            ->get()->getResultArray();
        CLI::write("Classroom Clashes (DB): " . count($classClashes), count($classClashes) > 0 ? 'red' : 'green');
        foreach ($classClashes as $cc) {
            CLI::write("  - Class ID: {$cc['classroom_id']} | Day: {$cc['day']} | Slot: {$cc['slot_number']} (Count: {$cc['cnt']})", 'red');
        }

        // Count teacher clashes from DB
        $teacherClashes = $db->table('schedule_entries')
            ->select('teacher_id, day, slot_number, COUNT(*) as cnt')
            ->where('schedule_id', 7)
            ->groupBy('teacher_id, day, slot_number')
            ->having('cnt > 1')
            ->get()->getResultArray();
        CLI::write("Teacher Clashes (DB): " . count($teacherClashes), count($teacherClashes) > 0 ? 'red' : 'green');
        
        CLI::write("\n--- Detailed Logs ---", 'cyan');
        foreach ($result['log'] as $log) {
            CLI::write($log);
        }
        
        if (!empty($result['conflicts'])) {
            CLI::write("\n--- Unplaced Loads (Conflicts) ---", 'red');
            foreach ($result['conflicts'] as $c) {
                CLI::write("Class: " . $c['classroom_name'] . " | Teacher: " . $c['teacher_name'] . " | Subject: " . $c['subject_name'] . " | Unplaced: " . $c['unplaced'] . " hours");
            }
            
            // Run classroom empty slots analysis
            CLI::write("\n--- Classroom Empty Slots Analysis ---", 'cyan');
            
            $classroomPlacements = [];
            $entries = $db->table('schedule_entries')
                ->where('schedule_id', 7)
                ->get()->getResultArray();
            foreach ($entries as $e) {
                $cId = $e['classroom_id'];
                $classroomPlacements[$cId] = ($classroomPlacements[$cId] ?? 0) + 1;
            }
            
            foreach ($classrooms as $c) {
                $cId = $c['id'];
                $placed = $classroomPlacements[$cId] ?? 0;
                $empty = 40 - $placed;
                CLI::write("Classroom: " . $c['name'] . " | Placed: $placed | Empty slots: $empty");
            }
            
            // Run failed blocks classification analysis
            CLI::write("\n--- Failed Blocks Classification Analysis ---", 'cyan');
            
            $activeDays = explode(',', $schedule['active_days']);
            $yearId = (int)$schedule['academic_year_id'];
            $periodId = (int)$schedule['academic_period_id'];
            
            // 1. Load active KBM slots per day
            $kbmSlotsByDay = [];
            $kbmPerDay = [];
            foreach ($activeDays as $day) {
                $slots = $db->table('schedule_timeslots')
                    ->where('day', $day)
                    ->where('slot_type', 'kbm')
                    ->where('is_active', 1)
                    ->orderBy('slot_number')
                    ->get()->getResultArray();
                $kbmSlotsByDay[$day] = $slots;
                $kbmPerDay[$day] = count($slots);
            }
            
            // 2. Load all placed entries grouped by classroom
            $entries = $db->table('schedule_entries')
                ->where('schedule_id', 7)
                ->get()->getResultArray();
            
            $placedByClass = [];
            $placedByTeacher = [];
            foreach ($entries as $e) {
                $cId = (int)$e['classroom_id'];
                $tId = (int)$e['teacher_id'];
                $day = (int)$e['day'];
                $slot = (int)$e['slot_number'];
                
                $placedByClass[$cId][$day][$slot] = true;
                $placedByTeacher[$tId][$day][$slot] = true;
            }
            
            // 3. Load all schedule loads
            $loads = $db->table('schedule_loads sl')
                ->select('sl.id, sl.teacher_id, sl.classroom_id, sl.hours_per_week, sl.split_config, t.name as teacher_name, ss.name as subject_name, c.name as classroom_name')
                ->join('teachers t', 't.id = sl.teacher_id')
                ->join('school_subjects ss', 'ss.id = sl.school_subject_id')
                ->join('classrooms c', 'c.id = sl.classroom_id')
                ->where('sl.academic_year_id', $yearId)
                ->where('sl.academic_period_id', $periodId)
                ->get()
                ->getResultArray();
                
            // Helper to parse blocks
            $helper = new class {
                public function parseSplitConfig(int $totalHours, string $splitConfig): array {
                    if (empty(trim($splitConfig))) {
                        return [$totalHours];
                    }
                    $blocks = array_filter(
                        array_map('intval', explode(',', $splitConfig)),
                        fn($b) => $b > 0
                    );
                    if (empty($blocks) || array_sum($blocks) !== $totalHours) {
                        return [$totalHours];
                    }
                    return array_values(array_slice($blocks, 0, 3));
                }
            };
            
            // 4. Blocked slots per teacher
            $teacherIds = array_unique(array_column($loads, 'teacher_id'));
            $blockedMap = [];
            if (!empty($teacherIds)) {
                $blockedRows = $db->table('schedule_availability')
                    ->whereIn('teacher_id', $teacherIds)
                    ->whereIn('day', $activeDays)
                    ->get()->getResultArray();
                foreach ($blockedRows as $b) {
                    $tid = (int)$b['teacher_id'];
                    $day = (int)$b['day'];
                    $slot = (int)$b['slot_number'];
                    if ($slot === 0) {
                        // All slots in this day are blocked
                        foreach ($kbmSlotsByDay[$day] ?? [] as $ks) {
                            $blockedMap[$tid][$day][(int)$ks['slot_number']] = true;
                        }
                    } else {
                        $blockedMap[$tid][$day][$slot] = true;
                    }
                }
            }
            
            // 5. Placed hours
            $filledPerLoad = [];
            $entriesGrouped = $db->table('schedule_entries')
                ->select('schedule_load_id, COUNT(*) as total')
                ->where('schedule_id', 7)
                ->groupBy('schedule_load_id')
                ->get()
                ->getResultArray();
            foreach ($entriesGrouped as $e) {
                $filledPerLoad[$e['schedule_load_id']] = (int)$e['total'];
            }
            
            // 6. Find failed blocks
            foreach ($loads as $load) {
                $lid = $load['id'];
                $totalHours = (int)$load['hours_per_week'];
                $blocks = $helper->parseSplitConfig($totalHours, $load['split_config'] ?? '');
                $totalNeeded = array_sum($blocks);
                $filled = $filledPerLoad[$lid] ?? 0;
                
                if ($filled >= $totalNeeded) {
                    continue;
                }
                
                $classId = (int)$load['classroom_id'];
                $teacherId = (int)$load['teacher_id'];
                
                // Find empty slots for this classroom
                $classroomEmptySlots = 0;
                $classroomEmptySlotsList = [];
                foreach ($activeDays as $day) {
                    foreach ($kbmSlotsByDay[$day] ?? [] as $ks) {
                        $sNum = (int)$ks['slot_number'];
                        if (!isset($placedByClass[$classId][$day][$sNum])) {
                            $classroomEmptySlots++;
                            $classroomEmptySlotsList[] = ['day' => $day, 'slot' => $sNum];
                        }
                    }
                }
                
                // Find how many of the classroom's empty slots are blocked for this teacher
                $teacherBlockedInClassroomEmpty = 0;
                $teacherTeachingElsewhereInClassroomEmpty = 0;
                
                foreach ($classroomEmptySlotsList as $slotInfo) {
                    $day = $slotInfo['day'];
                    $sNum = $slotInfo['slot'];
                    
                    if (isset($blockedMap[$teacherId][$day][$sNum])) {
                        $teacherBlockedInClassroomEmpty++;
                    } elseif (isset($placedByTeacher[$teacherId][$day][$sNum])) {
                        $teacherTeachingElsewhereInClassroomEmpty++;
                    }
                }
                
                // Classify
                $minBlock = min($blocks);
                if ($classroomEmptySlots < $minBlock) {
                    $category = 'NO_SLOT_CLASSROOM_FULL';
                } elseif ($classroomEmptySlots - $teacherBlockedInClassroomEmpty - $teacherTeachingElsewhereInClassroomEmpty < $minBlock) {
                    if ($classroomEmptySlots - $teacherBlockedInClassroomEmpty < $minBlock) {
                        $category = 'TEACHER_BLOCKED';
                    } else {
                        $category = 'TEACHER_BUSY_ELSEWHERE';
                    }
                } else {
                    $category = 'CONSTRAINT_CONFLICT';
                }
                
                CLI::write("Load ID: $lid | Class: " . $load['classroom_name'] . " | Teacher: " . $load['teacher_name'] . " | Subject: " . $load['subject_name']);
                CLI::write("  - Needed: $totalNeeded | Filled: $filled | Min Block Size: $minBlock");
                CLI::write("  - Classroom Empty Slots: $classroomEmptySlots");
                CLI::write("  - Teacher Blocked in these slots: $teacherBlockedInClassroomEmpty");
                CLI::write("  - Teacher Teaching elsewhere in these slots: $teacherTeachingElsewhereInClassroomEmpty");
                CLI::write("  - Category: $category");
            }
        }
    }
}
