<?php

namespace App\Http\Controllers\Api\CompetitionScores;

use App\Http\Controllers\Api\BaseApiController;
use App\Models\Competition;
use App\Services\CompetitionScores\CompetitionScoresContextService;
use App\Services\CompetitionScores\CompetitionScoresQueryService;
use App\Services\CompetitionScores\CompetitionScoresRosterService;
use App\Services\CompetitionScores\CompetitionScoresSaveService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;

class CompetitionScoresController extends BaseApiController
{
    private CompetitionScoresContextService $contextService;
    private CompetitionScoresQueryService $queryService;
    private CompetitionScoresRosterService $rosterService;
    private CompetitionScoresSaveService $saveService;

    public function __construct(
        CompetitionScoresContextService $contextService,
        CompetitionScoresQueryService $queryService,
        CompetitionScoresRosterService $rosterService,
        CompetitionScoresSaveService $saveService
    ) {
        parent::__construct();
        $this->contextService = $contextService;
        $this->queryService = $queryService;
        $this->rosterService = $rosterService;
        $this->saveService = $saveService;
    }

    public function index(Request $request): JsonResponse
    {
        $userId = (int) (auth()->id() ?? 0);
        [$assignments, $schoolYear, $semester] = $this->contextService->getTeacherContext($userId);

        $activeClassId = $this->contextService->resolveActiveClassId(
            $assignments,
            (int) $request->query('class_section_id', 0)
        );
        $activeClassName = $this->contextService->getActiveClassName($assignments, $activeClassId);

        if (empty($assignments) || $activeClassId <= 0) {
            return response()->json([
                'ok' => true,
                'competitions' => [],
                'activeClassId' => $activeClassId,
                'activeClassName' => $activeClassName,
                'questionCounts' => [],
                'scoreCounts' => [],
                'studentTotal' => 0,
                'sectionMap' => $this->contextService->getClassSectionMap(),
                'schoolYear' => $schoolYear,
                'semester' => $semester,
                'hasClasses' => false,
            ]);
        }

        $competitions = $this->queryService->getCompetitionsForClass($activeClassId, $schoolYear, $semester);
        $competitionIds = array_values(array_filter(array_map(static function ($row) {
            return (int) ($row['id'] ?? 0);
        }, $competitions)));

        return response()->json([
            'ok' => true,
            'competitions' => $competitions,
            'activeClassId' => $activeClassId,
            'activeClassName' => $activeClassName,
            'questionCounts' => $this->queryService->getQuestionCounts($competitionIds, $activeClassId),
            'scoreCounts' => $this->queryService->getScoreCounts($competitionIds, $activeClassId),
            'studentTotal' => $this->rosterService->getClassStudentCount($activeClassId, $schoolYear),
            'sectionMap' => $this->contextService->getClassSectionMap(),
            'schoolYear' => $schoolYear,
            'semester' => $semester,
            'hasClasses' => true,
        ]);
    }

    public function edit(Request $request, int $id): JsonResponse
    {
        $userId = (int) (auth()->id() ?? 0);
        [$assignments, $schoolYear, $semester] = $this->contextService->getTeacherContext($userId);
        $allowedClassIds = $this->contextService->getAllowedClassIds($assignments);

        if (empty($allowedClassIds)) {
            return response()->json([
                'ok' => false,
                'message' => 'No class assignments found for your account.',
            ], 403);
        }

        $competition = Competition::query()->find($id);
        if (!$competition) {
            return response()->json([
                'ok' => false,
                'message' => 'Competition not found.',
            ], 404);
        }

        $isLocked = (bool) $competition->is_locked;
        $lockedClassId = (int) ($competition->class_section_id ?? 0);
        $requestedClassId = (int) $request->query('class_section_id', 0);
        $activeClassId = $this->contextService->resolveActiveClassId($assignments, $requestedClassId);
        $classSectionId = $lockedClassId > 0 ? $lockedClassId : $activeClassId;

        if ($classSectionId <= 0) {
            return response()->json([
                'ok' => false,
                'message' => 'Select a class section before entering scores.',
            ], 422);
        }

        if (!in_array($classSectionId, $allowedClassIds, true)) {
            return response()->json([
                'ok' => false,
                'message' => 'You are not assigned to that class.',
            ], 403);
        }

        $competitionArray = $competition->toArray();
        $students = $this->rosterService->getStudentsForCompetition($competitionArray, $classSectionId);
        $scoreMap = $this->saveService->getScoreMap($id, $classSectionId);
        $questionCount = $this->queryService->getQuestionCountForCompetition($id, $classSectionId);
        $classStudentCount = $this->rosterService->getClassStudentCount(
            $classSectionId,
            $competitionArray['school_year'] ?? $schoolYear
        );

        return response()->json([
            'ok' => true,
            'competition' => $competitionArray,
            'students' => $students,
            'scoreMap' => $scoreMap,
            'classSectionId' => $classSectionId,
            'classSectionName' => $this->contextService->getActiveClassName($assignments, $classSectionId),
            'classStudentCount' => $classStudentCount,
            'questionCount' => $questionCount,
            'classSelectionLocked' => $lockedClassId > 0,
            'isLocked' => $isLocked,
            'schoolYear' => $schoolYear,
            'semester' => $semester,
        ]);
    }

    public function save(Request $request, int $id): JsonResponse
    {
        $userId = (int) (auth()->id() ?? 0);
        [$assignments] = $this->contextService->getTeacherContext($userId);
        $allowedClassIds = $this->contextService->getAllowedClassIds($assignments);

        if (empty($allowedClassIds)) {
            return response()->json([
                'ok' => false,
                'message' => 'No class assignments found for your account.',
            ], 403);
        }

        $competition = Competition::query()->find($id);
        if (!$competition) {
            return response()->json([
                'ok' => false,
                'message' => 'Competition not found.',
            ], 404);
        }

        if ((bool) $competition->is_locked) {
            return response()->json([
                'ok' => false,
                'message' => 'Competition is locked. You cannot update scores.',
            ], 423);
        }

        $lockedClassId = (int) ($competition->class_section_id ?? 0);
        $classSectionId = $lockedClassId > 0 ? $lockedClassId : (int) $request->input('class_section_id', 0);

        if ($classSectionId <= 0) {
            return response()->json([
                'ok' => false,
                'message' => 'Select a class section before saving scores.',
            ], 422);
        }

        if (!in_array($classSectionId, $allowedClassIds, true)) {
            return response()->json([
                'ok' => false,
                'message' => 'You are not assigned to that class.',
            ], 403);
        }

        $scores = $request->input('scores', []);
        $scores = is_array($scores) ? $scores : [];
        [$cleanScores, $invalidScores] = $this->saveService->filterScores($scores);

        if (!empty($invalidScores)) {
            return response()->json([
                'ok' => false,
                'message' => 'Scores must be whole numbers (no decimals).',
                'invalidScores' => $invalidScores,
            ], 422);
        }

        $this->saveService->saveScores($id, $classSectionId, $cleanScores);

        return response()->json([
            'ok' => true,
            'message' => 'Scores saved.',
            'savedCount' => count($cleanScores),
        ]);
    }
}
