<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Builder;
use App\Models\BaseModel;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Support\Facades\DB;

class StudentClass extends BaseModel
{
    protected $table = 'student_class';

    protected $fillable = [
        'student_id',
        'class_section_id',
        'is_event_only',
        'semester',
        'school_year',
        'description',
        'created_at',
        'updated_at',
        'updated_by',
    ];

    public $timestamps = true;

    protected $casts = [
        'student_id'       => 'integer',
        'school_id'        => 'integer',
        'class_section_id' => 'integer',
        'is_event_only'    => 'boolean',
        'updated_by'       => 'integer',
        'created_at'       => 'datetime',
        'updated_at'       => 'datetime',
    ];

    /* ============================================================
     * Relationships (optional but recommended)
     * ============================================================
     */

    public function student(): BelongsTo
    {
        return $this->belongsTo(Student::class, 'student_id');
    }

    public function classSection(): BelongsTo
    {
        // Your CI joins on classSection.class_section_id
        return $this->belongsTo(ClassSection::class, 'class_section_id', 'class_section_id');
    }

    public function school(): BelongsTo
    {
        return $this->belongsTo(School::class, 'school_id');
    }

    public function updater(): BelongsTo
    {
        return $this->belongsTo(User::class, 'updated_by'); // change to Admin if needed
    }

    /* ============================================================
     * Scopes
     * ============================================================
     */

    /**
     * Scope: only students active for classes/attendance (joins students).
     * Mirrors CI active().
     */
    public function scopeActive(Builder $q): Builder
    {
        return $q->select('student_class.*')
            ->join('students', 'students.id', '=', 'student_class.student_id')
            ->where('students.is_active', 1);
    }

    public function scopeForSection(Builder $q, int $classSectionId): Builder
    {
        return $q->where('student_class.class_section_id', $classSectionId);
    }

    public function scopeForYear(Builder $q, ?string $schoolYear): Builder
    {
        if ($schoolYear === null || trim($schoolYear) === '') return $q;
        return $q->where('student_class.school_year', $schoolYear);
    }

    public function scopeNonEvent(Builder $q): Builder
    {
        return $q->where('student_class.is_event_only', 0);
    }

    /* ============================================================
     * CI-compatible methods (rewritten Laravel-style)
     * ============================================================
     */

    public static function getClassSectionNameByStudentId(int $studentId): ?string
    {
        return DB::table('student_class as sc')
            ->join('classSection as cs', 'cs.class_section_id', '=', 'sc.class_section_id')
            ->where('sc.student_id', $studentId)
            ->value('cs.class_section_name');
    }

    /**
     * Get all students in a specific class section (optionally scoped to schoolYear), active students only.
     * Mirrors getClassStudents()
     */
    public static function getClassStudents(int $classSectionId, ?string $schoolYear = null)
    {
        return static::query()
            ->active()
            ->forSection($classSectionId)
            ->forYear($schoolYear)
            ->get();
    }

    /**
     * Return class section names for a student in a given school year.
     * Mirrors getClassSectionsByStudentId()
     *
     * @return array|string
     */
    public static function getClassSectionsByStudentId($studentId, string $schoolYear, bool $asArray = false)
    {
        $names = DB::table('student_class as sc')
            ->join('classSection as cs', 'cs.class_section_id', '=', 'sc.class_section_id')
            ->where('sc.student_id', $studentId)
            ->whereNotNull('sc.class_section_id')
            ->where('sc.school_year', $schoolYear)
            ->orderBy('cs.class_section_name', 'asc')
            ->pluck('cs.class_section_name')
            ->filter(fn ($v) => $v !== null && trim((string)$v) !== '')
            ->unique()
            ->values()
            ->all();

        return $asArray ? $names : (!empty($names) ? implode(', ', $names) : '');
    }

    /**
     * Return class section names for a student in a given school year, with optional event flag.
     * Mirrors getClassSectionsByStudentIdWithFlags()
     *
     * @return array|string
     */
    public static function getClassSectionsByStudentIdWithFlags($studentId, string $schoolYear, bool $asArray = false)
    {
        $rows = DB::table('student_class as sc')
            ->select('cs.class_section_name', 'sc.is_event_only')
            ->join('classSection as cs', 'cs.class_section_id', '=', 'sc.class_section_id')
            ->where('sc.student_id', $studentId)
            ->whereNotNull('sc.class_section_id')
            ->where('sc.school_year', $schoolYear)
            ->orderBy('cs.class_section_name', 'asc')
            ->get();

        $names = [];
        foreach ($rows as $r) {
            $name = $r->class_section_name ?? null;
            if (!$name) continue;

            $isEvent = (int)($r->is_event_only ?? 0) === 1;
            $names[] = $isEvent ? ($name . ' (Event)') : $name;
        }

        $names = array_values(array_unique(array_filter($names)));

        return $asArray ? $names : (!empty($names) ? implode(', ', $names) : '');
    }

    /**
     * Return class_section_id values for a student/year.
     * Mirrors getClassSectionIdsByStudentId()
     */
    public static function getClassSectionIdsByStudentId($studentId, string $schoolYear): array
    {
        $ids = DB::table('student_class')
            ->where('student_id', $studentId)
            ->whereNotNull('class_section_id')
            ->where('school_year', $schoolYear)
            ->pluck('class_section_id')
            ->map(fn ($v) => (int) $v)
            ->filter(fn ($v) => $v > 0)
            ->unique()
            ->values()
            ->all();

        return $ids;
    }

    /**
     * Mirrors getStudentsByClassSectionIds()
     * Returns array rows (not models) like CI.
     */
    public static function getStudentsByClassSectionIds(array $classSectionIds): array
    {
        $ids = array_values(array_unique(array_filter(array_map('intval', $classSectionIds))));
        if (empty($ids)) return [];

        return DB::table('student_class as sc')
            ->selectRaw('
                students.id as student_id,
                students.firstname,
                students.lastname,
                students.school_id,
                students.is_new,
                students.photo_consent,
                students.age,
                sc.school_year,
                sc.class_section_id
            ')
            ->join('students', 'students.id', '=', 'sc.student_id')
            ->whereIn('sc.class_section_id', $ids)
            ->where('students.is_active', 1)
            ->get()
            ->map(fn ($r) => (array) $r)
            ->all();
    }

    /**
     * Get the class ID (grade) for a specific student.
     * Mirrors getStudentGrade()
     */
    public static function getStudentGrade(int $studentId): string
    {
        $sc = static::query()
            ->where('student_id', $studentId)
            ->where('is_event_only', 0)
            ->orderByDesc('created_at')
            ->first();

        if (!$sc || !$sc->class_section_id) {
            return 'N/A';
        }

        $classId = DB::table('classSection')
            ->where('class_section_id', $sc->class_section_id)
            ->value('class_id');

        return $classId ?: 'N/A';
    }

    /**
     * Return true if the student has at least one non-event class assignment for the year.
     * Mirrors hasNonEventAssignment()
     */
    public static function hasNonEventAssignment(int $studentId, string $schoolYear): bool
    {
        return static::query()
            ->where('student_id', $studentId)
            ->where('school_year', $schoolYear)
            ->where('is_event_only', 0)
            ->exists();
    }

    /**
     * Return student counts per class_section_id, optionally scoped to a school year.
     * Mirrors getStudentCountsBySection()
     *
     * @return array<int|string,int> Map of class_section_id => count
     */
    public static function getStudentCountsBySection(?string $schoolYear = null): array
    {
        $q = DB::table('student_class as sc')
            ->selectRaw('sc.class_section_id, COUNT(*) as total')
            ->join('students', 'students.id', '=', 'sc.student_id')
            ->where('students.is_active', 1)
            ->whereNotNull('sc.class_section_id')
            ->groupBy('sc.class_section_id');

        if ($schoolYear !== null && trim($schoolYear) !== '') {
            $q->where('sc.school_year', $schoolYear);
        }

        $rows = $q->get();

        $out = [];
        foreach ($rows as $r) {
            $cid = $r->class_section_id;
            if ($cid === null || $cid === '') continue;
            $out[$cid] = (int) ($r->total ?? 0);
        }

        return $out;
    }

    /* ============================================================
     * Optional validation helper
     * ============================================================
     */
    public static function rules(bool $updating = false): array
    {
        $req = $updating ? 'sometimes' : 'required';

        return [
            'student_id'       => [$req, 'integer', 'min:1', 'exists:students,id'],
            'school_id'        => ['nullable', 'integer', 'min:1'],
            'class_section_id' => ['nullable', 'integer'],
            'school_year'      => [$req, 'string', 'max:20'],
            'is_event_only'    => ['nullable', 'boolean'],
            'description'      => ['nullable', 'string', 'max:2000'],
            'updated_by'       => ['nullable', 'integer'],
        ];
    }
}