<?php

namespace App\Services\ClassPreparation;

use App\Models\ClassSection;

class ClassPreparationService
{
    private ClassPreparationContextService $context;
    private ClassPreparationRosterService $roster;
    private ClassPreparationInventoryService $inventory;
    private ClassPreparationCalculatorService $calculator;
    private ClassPreparationAdjustmentService $adjustments;
    private ClassPreparationLogService $logs;

    public function __construct(
        ClassPreparationContextService $context,
        ClassPreparationRosterService $roster,
        ClassPreparationInventoryService $inventory,
        ClassPreparationCalculatorService $calculator,
        ClassPreparationAdjustmentService $adjustments,
        ClassPreparationLogService $logs
    ) {
        $this->context = $context;
        $this->roster = $roster;
        $this->inventory = $inventory;
        $this->calculator = $calculator;
        $this->adjustments = $adjustments;
        $this->logs = $logs;
    }

    public function listPrep(?string $schoolYear = null, ?string $semester = null): array
    {
        $schoolYear = $schoolYear ?: $this->context->getSchoolYear();
        $semester = $semester ?: $this->context->getSemester();
        $allowed = $this->calculator->getAllowedCategories();
        $limitToSemester = $this->context->hasRosterForSemester($schoolYear, $semester);

        $classSections = $this->roster->getClassSectionStudentCounts($schoolYear, $semester, $limitToSemester);

        $inventoryMap = $this->inventory->buildAvailability($schoolYear, $semester, $limitToSemester, $allowed);
        $requiredTotals = array_fill_keys($allowed, 0);
        $results = [];

        foreach ($classSections as $row) {
            $classSectionId = (string) $row->class_section_id;
            $studentCount = (int) $row->student_count;
            $classLevel = $this->calculator->getClassLevelBySection($classSectionId);
            $className = ClassSection::getClassSectionNameBySectionId($classSectionId);

            $baseItems = $this->calculator->calculatePrepItems($studentCount, $classLevel, $classSectionId);
            [$baseItems, $adjMap] = $this->adjustments->applyAdjustments($baseItems, $classSectionId, $schoolYear);

            foreach ($allowed as $cat) {
                $requiredTotals[$cat] += (int) ($baseItems[$cat] ?? 0);
            }

            $oldSnap = $this->logs->getLatestLog($classSectionId, $schoolYear);
            $oldPrep = $oldSnap ? (array) ($oldSnap->prep_data ?? []) : [];
            $hasChanged = $this->logs->hasPrepChanged($baseItems, $oldPrep);

            $results[] = [
                'class_section'    => $className,
                'class_section_id' => $classSectionId,
                'student_count'    => $studentCount,
                'class_level'      => $classLevel,
                'prep_items'       => $baseItems,
                'needs_print'      => $hasChanged,
                'last_printed_at'  => $oldSnap?->created_at,
                'adjustments'      => $adjMap,
            ];
        }

        $shortages = [];
        foreach ($requiredTotals as $item => $reqQty) {
            $have = (int) ($inventoryMap[$item] ?? 0);
            if ($have < (int) $reqQty) {
                $shortages[$item] = (int) $reqQty - $have;
            }
        }

        return [
            'schoolYear' => $schoolYear,
            'semester' => $semester,
            'results' => $results,
            'totals' => $requiredTotals,
            'shortages' => $shortages,
        ];
    }

    public function markPrinted(string $schoolYear, string $semester, array $classSectionIds): int
    {
        $limitToSemester = $this->context->hasRosterForSemester($schoolYear, $semester);
        $ids = array_values(array_unique(array_filter(array_map('strval', $classSectionIds))));
        $now = $this->utcNow();
        $count = 0;

        foreach ($ids as $classSectionId) {
            $studentCount = $this->roster->getStudentCountForSection($schoolYear, $semester, $limitToSemester, $classSectionId);
            $classLevel = $this->calculator->getClassLevelBySection($classSectionId);
            $className = ClassSection::getClassSectionNameBySectionId($classSectionId) ?? $classSectionId;

            $items = $this->calculator->calculatePrepItems($studentCount, $classLevel, $classSectionId);
            [$items] = $this->adjustments->applyAdjustments($items, $classSectionId, $schoolYear);

            if ($this->logs->createLog($classSectionId, $className, $schoolYear, $items, $now)) {
                $count++;
            }
        }

        return $count;
    }

    private function utcNow(): string
    {
        if (function_exists('utc_now')) {
            return (string) utc_now();
        }
        return now('UTC')->toDateTimeString();
    }
}
