<?php

namespace App\Services\ClassPrep;

use App\Models\Configuration;
use Illuminate\Support\Facades\DB;

class StickerCountService
{
    public function listAll(?string $schoolYear = null, ?string $semester = null): array
    {
        $schoolYear = $this->resolveSchoolYear($schoolYear);
        $semester = $this->resolveSemester($semester);

        return $this->buildStickerCounts($schoolYear, $semester, null, $this->specialMapWithKg());
    }

    public function listForClass(?string $schoolYear, ?string $semester, int $classSectionId): array
    {
        $schoolYear = $this->resolveSchoolYear($schoolYear);
        $semester = $this->resolveSemester($semester);

        return $this->buildStickerCounts($schoolYear, $semester, $classSectionId, $this->specialMapWithoutKg());
    }

    private function resolveSchoolYear(?string $schoolYear): string
    {
        return $schoolYear && trim($schoolYear) !== ''
            ? $schoolYear
            : (string) Configuration::getConfig('school_year');
    }

    private function resolveSemester(?string $semester): string
    {
        return $semester && trim($semester) !== ''
            ? $semester
            : (string) Configuration::getConfig('semester');
    }

    private function buildStickerCounts(string $schoolYear, string $semester, ?int $classSectionId, array $specialMap): array
    {
        $builder = DB::table('student_class as sc')
            ->select(
                'sc.student_id',
                's.firstname',
                's.lastname',
                's.is_new',
                'cs.class_section_name AS grade_label'
            )
            ->join('students as s', 's.id', '=', 'sc.student_id')
            ->join('classSection as cs', 'cs.class_section_id', '=', 'sc.class_section_id')
            ->join('classes as c', 'c.id', '=', 'cs.class_id')
            ->where('sc.school_year', $schoolYear);

        if ($classSectionId !== null && $classSectionId > 0) {
            $builder->where('sc.class_section_id', $classSectionId);
        }

        $rows = $builder->get()->toArray();

        $students = [];
        $totalPrimary = 0;
        $totalSecondary = 0;

        foreach ($rows as $row) {
            $grade = trim((string) ($row->grade_label ?? ''));
            if ($grade === '' || $this->isYouth($grade)) {
                continue;
            }

            $isNew = (int) ($row->is_new ?? 0) === 1;
            [$primary, $secondary] = $this->calculateStickerCounts($grade, $isNew, $specialMap);

            $totalPrimary += $primary;
            $totalSecondary += $secondary;

            $students[] = [
                'student_id' => (int) ($row->student_id ?? 0),
                'firstname' => trim((string) ($row->firstname ?? '')),
                'lastname' => trim((string) ($row->lastname ?? '')),
                'grade_label' => $grade,
                'primary_count' => $primary,
                'secondary_count' => $secondary,
            ];
        }

        return [
            'schoolYear' => $schoolYear,
            'semester' => $semester,
            'classSectionId' => $classSectionId,
            'students' => $students,
            'totals' => [
                'primary' => $totalPrimary,
                'secondary' => $totalSecondary,
                'students' => count($students),
            ],
        ];
    }

    private function calculateStickerCounts(string $grade, bool $isNew, array $specialMap): array
    {
        $primary = 0;
        $secondary = 0;

        if (array_key_exists($grade, $specialMap)) {
            $primary = (int) $specialMap[$grade];
            $secondary = 0;
        } elseif ($this->isUpperBlock($grade)) {
            if ($isNew) {
                $primary = 4;
                $secondary = 0;
            } else {
                $primary = $this->isGrade5($grade) ? 3 : 2;
                $secondary = max(0, 4 - $primary);
            }
        } else {
            $primary = 4;
            $secondary = 0;
        }

        return [$primary, $secondary];
    }

    private function isUpperBlock(string $grade): bool
    {
        return (bool) preg_match('/^(3|4|5|6|7|8)(-[AB])?$/', trim($grade));
    }

    private function isGrade5(string $grade): bool
    {
        return (bool) preg_match('/^5(\-|$)/', trim($grade));
    }

    private function isYouth(string $grade): bool
    {
        return (bool) preg_match('/^youth(?:\b|-)/i', trim($grade));
    }

    private function specialMapWithKg(): array
    {
        return [
            'KG' => 1,
            '1-A' => 3,
            '1-B' => 4,
            '2-A' => 5,
            '2-B' => 5,
            '9' => 2,
        ];
    }

    private function specialMapWithoutKg(): array
    {
        return [
            '1-A' => 3,
            '1-B' => 4,
            '2-A' => 5,
            '2-B' => 5,
            '9' => 2,
        ];
    }
}
