<?php

declare(strict_types=1);

namespace App\Services\Badges;

use App\Models\Student;
use App\Models\StudentClass;
use Illuminate\Support\Facades\DB;

class BadgeStudentLookupService
{
    public function __construct(
        protected BadgeTextFormatter $formatter
    ) {
    }

    /**
     * Active student roster for the badge picker.
     *
     * @param  int[]  $selectedStudentIds
     * @return array<int, array<string, mixed>>
     */
    public function fetchStudentList(?string $schoolYear, array $selectedStudentIds = []): array
    {
        $selectedStudentIds = $this->formatter->normalizeIds($selectedStudentIds);

        $query = DB::table('students')
            ->leftJoin('student_class as sc', function ($join) use ($schoolYear) {
                $join->on('sc.student_id', '=', 'students.id');

                if (!empty($schoolYear)) {
                    $join->where('sc.school_year', '=', $schoolYear);
                }
            })
            ->leftJoin('classSection as cs', 'cs.class_section_id', '=', 'sc.class_section_id')
            ->select([
                'students.id as student_id',
                'students.firstname',
                'students.lastname',
                'students.registration_grade',
                'students.school_id',
                'students.school_year',
                DB::raw("GROUP_CONCAT(DISTINCT cs.class_section_name ORDER BY cs.class_section_name SEPARATOR ', ') as class_section_name"),
            ])
            ->where('students.is_active', 1)
            ->groupBy(
                'students.id',
                'students.firstname',
                'students.lastname',
                'students.registration_grade',
                'students.school_id',
                'students.school_year'
            )
            ->orderBy('students.lastname')
            ->orderBy('students.firstname');

        if (!empty($selectedStudentIds)) {
            $query->whereIn('students.id', $selectedStudentIds);
        } elseif (!empty($schoolYear)) {
            $query->where(function ($q) use ($schoolYear) {
                $q->where('students.school_year', $schoolYear)
                    ->orWhereNotNull('sc.student_id');
            });
        }

        $rows = array_map(static fn ($row) => (array) $row, $query->get()->all());

        $out = [];
        foreach ($rows as $row) {
            $studentId = (int) ($row['student_id'] ?? 0);
            if ($studentId <= 0) {
                continue;
            }

            $schoolId = trim((string) ($row['school_id'] ?? ''));
            if ($schoolId === '' || !preg_match('/^[A-Za-z0-9_-]+$/', $schoolId)) {
                continue;
            }

            $out[] = [
                'student_id' => $studentId,
                'firstname' => (string) ($row['firstname'] ?? ''),
                'lastname' => (string) ($row['lastname'] ?? ''),
                'role_name' => 'Student',
                'roles' => 'Student',
                'registration_grade' => (string) ($row['registration_grade'] ?? ''),
                'class_section_name' => $this->formatter->norm((string) ($row['class_section_name'] ?? '')),
                'school_id' => $schoolId,
                'school_year' => (string) ($row['school_year'] ?? $schoolYear ?? ''),
            ];
        }

        return $out;
    }

    /**
     * Load students for badge printing: valid school_id (QR payload), ordered by name.
     *
     * @param  int[]  $studentIds
     * @return array<int, array{student_id:int, fullname:string, grade:string, academic_year:string, school_id:string}>
     */
    public function fetchForBadges(array $studentIds, ?string $schoolYear): array
    {
        $studentIds = $this->formatter->normalizeIds($studentIds);
        if ($studentIds === []) {
            return [];
        }

        $rows = Student::query()
            ->whereIn('id', $studentIds)
            ->where('is_active', 1)
            ->orderBy('lastname')
            ->orderBy('firstname')
            ->get();

        $out = [];
        foreach ($rows as $student) {
            $schoolId = trim((string) ($student->school_id ?? ''));
            if ($schoolId === '' || !preg_match('/^[A-Za-z0-9_-]+$/', $schoolId)) {
                continue;
            }

            $fullname = Student::getFullName($student->toArray());
            $grade = $this->resolveGrade((int) $student->id, (string) ($student->registration_grade ?? ''));

            $academicYear = $schoolYear ?? (string) ($student->school_year ?? '');
            $academicYear = $this->formatter->norm($academicYear);

            $out[] = [
                'student_id' => (int) $student->id,
                'fullname' => $fullname !== '' ? $fullname : 'Student',
                'grade' => $grade,
                'academic_year' => $academicYear,
                'school_id' => $schoolId,
            ];
        }

        return $out;
    }

    protected function resolveGrade(int $studentId, string $registrationGrade): string
    {
        $registrationGrade = $this->formatter->norm($registrationGrade);
        if ($registrationGrade !== '') {
            return $registrationGrade;
        }

        try {
            $g = StudentClass::getStudentGrade($studentId);
            $g = $this->formatter->norm((string) $g);

            return $g !== '' ? $g : '—';
        } catch (\Throwable) {
            return '—';
        }
    }
}
