<?php

namespace App\Models;

use CodeIgniter\Model;

class ScheduleLoadModel extends Model
{
    protected $table      = 'schedule_loads';
    protected $primaryKey = 'id';

    protected $allowedFields = [
        'schedule_id', 'academic_year_id', 'academic_period_id',
        'teacher_id', 'school_subject_id', 'classroom_id',
        'hours_per_week', 'split_config', 'split_order', 'notes',
    ];

    protected $useTimestamps = true;

    // -------------------------------------------------------
    // VALIDASI SPLIT CONFIG
    // -------------------------------------------------------
    
    /**
     * Validasi split_config
     * @param int $totalJam Total jam per minggu
     * @param string $splitConfig String split, contoh "2,2" atau "3,2,1"
     * @return array ['valid' => bool, 'message' => string, 'blocks' => array]
     */
    public function validateSplitConfig(int $totalJam, string $splitConfig): array
    {
        // Kosongkan = default satu blok (total jam)
        if (empty(trim($splitConfig))) {
            return [
                'valid'   => true,
                'message' => '',
                'blocks'  => [$totalJam]
            ];
        }

        // Parse string menjadi array integer
        $blocks = array_map('intval', explode(',', $splitConfig));
        
        // Filter angka 0
        $blocks = array_filter($blocks, fn($b) => $b > 0);
        
        if (empty($blocks)) {
            return [
                'valid'   => false,
                'message' => 'Pembagian blok tidak valid. Contoh: 2,2 atau 3,2',
                'blocks'  => []
            ];
        }

        // Aturan 1: Minimal 1 blok, maksimal 3 blok
        $blockCount = count($blocks);
        if ($blockCount < 1 || $blockCount > 3) {
            return [
                'valid'   => false,
                'message' => 'Jumlah blok minimal 1 dan maksimal 3 (contoh: 2,2 atau 3,2,1)',
                'blocks'  => []
            ];
        }

        // Aturan 2: Setiap blok minimal 1 jam, maksimal 3 jam
        foreach ($blocks as $block) {
            if ($block < 1 || $block > 3) {
                return [
                    'valid'   => false,
                    'message' => 'Setiap blok minimal 1 jam dan maksimal 3 jam',
                    'blocks'  => []
                ];
            }
        }

        // Aturan 3: Total blok harus sama dengan hours_per_week
        $totalBlocks = array_sum($blocks);
        if ($totalBlocks !== $totalJam) {
            return [
                'valid'   => false,
                'message' => "Total pembagian blok ({$totalBlocks} jam) tidak sama dengan total jam ({$totalJam} jam)",
                'blocks'  => []
            ];
        }

        return [
            'valid'   => true,
            'message' => '',
            'blocks'  => $blocks
        ];
    }

    /**
     * Ambil split_config sebagai array
     */
    public function getSplitArray(int $id): array
    {
        $load = $this->find($id);
        if (!$load || empty($load['split_config'])) {
            $total = (int)($load['hours_per_week'] ?? 0);
            return [$total];
        }
        
        $blocks = array_map('intval', explode(',', $load['split_config']));
        return array_filter($blocks, fn($b) => $b > 0);
    }

    /**
     * Generate saran split otomatis berdasarkan total jam
     * Aturan: 
     * - 1-3 jam → 1 blok
     * - 4 jam → 2,2
     * - 5 jam → 3,2
     * - 6 jam → 3,3 (prioritas) atau 2,2,2
     * - 7 jam → 3,2,2
     * - 8 jam → 3,3,2
     * - 9 jam → 3,3,3
     */
    public function suggestSplit(int $totalJam): string
    {
        if ($totalJam <= 3) {
            return (string)$totalJam;
        }
        
        if ($totalJam === 4) {
            return '2,2';
        }
        
        if ($totalJam === 5) {
            return '3,2';
        }
        
        if ($totalJam === 6) {
            return '3,3';
        }
        
        if ($totalJam === 7) {
            return '3,2,2';
        }
        
        if ($totalJam === 8) {
            return '3,3,2';
        }
        
        if ($totalJam === 9) {
            return '3,3,3';
        }
        
        // Untuk 10 jam ke atas, gunakan 3,3,3 + sisa
        $base = 9;
        $remain = $totalJam - 9;
        if ($remain <= 0) return '3,3,3';
        
        $sisaBlok = min($remain, 3);
        return "3,3,{$sisaBlok}";
    }

    // -------------------------------------------------------
    // QUERY EXISTING (TIDAK BERUBAH)
    // -------------------------------------------------------

    public function getWithRelations(int $yearId, int $periodId): array
    {
        return $this->db->table('schedule_loads sl')
            ->select([
                'sl.*',
                'CONCAT(t.nip, " - ", t.name) as teacher_label',
                't.name as teacher_name',
                't.nip as teacher_nip',
                'ss.name as subject_name',
                'ss.code as subject_code',
                'c.name as classroom_name',
                'g.name as grade_name',
                'm.name as major_name',
            ])
            ->join('teachers t', 't.id = sl.teacher_id', 'left')
            ->join('school_subjects ss', 'ss.id = sl.school_subject_id', 'left')
            ->join('classrooms c', 'c.id = sl.classroom_id', 'left')
            ->join('grades g', 'g.id = c.grade_id', 'left')
            ->join('majors m', 'm.id = c.major_id', 'left')
            ->where('sl.academic_year_id', $yearId)
            ->where('sl.academic_period_id', $periodId)
            ->orderBy('t.name')
            ->orderBy('ss.name')
            ->orderBy('c.name')
            ->get()->getResultArray();
    }

    public function getSummaryByTeacher(int $yearId, int $periodId): array
    {
        return $this->db->table('schedule_loads sl')
            ->select([
                't.id as teacher_id',
                't.name as teacher_name',
                't.nip',
                'COUNT(sl.id) as total_entries',
                'SUM(sl.hours_per_week) as total_hours',
            ])
            ->join('teachers t', 't.id = sl.teacher_id', 'left')
            ->where('sl.academic_year_id', $yearId)
            ->where('sl.academic_period_id', $periodId)
            ->groupBy('t.id')
            ->orderBy('t.name')
            ->get()->getResultArray();
    }

    public function isDuplicate(int $teacherId, int $subjectId, int $classroomId, int $yearId, int $periodId, ?int $excludeId = null): bool
    {
        $builder = $this->where('teacher_id', $teacherId)
                        ->where('school_subject_id', $subjectId)
                        ->where('classroom_id', $classroomId)
                        ->where('academic_year_id', $yearId)
                        ->where('academic_period_id', $periodId);
        if ($excludeId) {
            $builder->where('id !=', $excludeId);
        }
        return $builder->countAllResults() > 0;
    }

    public function getForGenerator(int $yearId, int $periodId): array
    {
        return $this->db->table('schedule_loads sl')
            ->select([
                'sl.*',
                't.name as teacher_name',
                'ss.name as subject_name',
                'ss.code as subject_code',
                'c.name as classroom_name',
                'c.grade_id',
                'c.major_id',
            ])
            ->join('teachers t', 't.id = sl.teacher_id', 'left')
            ->join('school_subjects ss', 'ss.id = sl.school_subject_id', 'left')
            ->join('classrooms c', 'c.id = sl.classroom_id', 'left')
            ->where('sl.academic_year_id', $yearId)
            ->where('sl.academic_period_id', $periodId)
            ->get()->getResultArray();
    }

    // -------------------------------------------------------
    // DELETE ALL METHODS
    // -------------------------------------------------------

    public function deleteAllByPeriod(int $yearId, int $periodId): int
    {
        return $this->where('academic_year_id', $yearId)
                    ->where('academic_period_id', $periodId)
                    ->delete();
    }

    public function deleteAllByTeacher(int $yearId, int $periodId, int $teacherId): int
    {
        return $this->where('academic_year_id', $yearId)
                    ->where('academic_period_id', $periodId)
                    ->where('teacher_id', $teacherId)
                    ->delete();
    }

    public function getGroupedByGrade(int $yearId, int $periodId): array
    {
        $rows = $this->db->table('schedule_loads sl')
            ->select([
                'sl.*',
                't.name as teacher_name',
                't.nip',
                'ss.name as subject_name',
                'ss.code',
                'c.name as classroom_name',
                'c.id as classroom_id',
                'g.name as grade_name',
                'g.id as grade_id',
                'g.order as grade_order',
                'm.name as major_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')
            ->join('grades g', 'g.id = c.grade_id', 'left')
            ->join('majors m', 'm.id = c.major_id', 'left')
            ->where('sl.academic_year_id', $yearId)
            ->where('sl.academic_period_id', $periodId)
            ->orderBy('g.order', 'ASC')
            ->orderBy('g.name', 'ASC')
            ->orderBy('c.name', 'ASC')
            ->get()
            ->getResultArray();

        $grouped = [];
        foreach ($rows as $row) {
            $gradeId = $row['grade_id'] ?? 0;
            $gradeName = $row['grade_name'] ?? 'Tanpa Kelas';
            $gradeOrder = $row['grade_order'] ?? 999;
            
            if (!isset($grouped[$gradeId])) {
                $grouped[$gradeId] = [
                    'grade_id' => $gradeId,
                    'grade_name' => $gradeName,
                    'grade_order' => $gradeOrder,
                    'loads' => [],
                ];
            }
            $grouped[$gradeId]['loads'][] = $row;
        }
        
        usort($grouped, fn($a, $b) => $a['grade_order'] <=> $b['grade_order']);
        
        return $grouped;
    }
}