<?php

namespace App\Http\Controllers\Api\ClassProgress;

use App\Http\Controllers\Api\Core\BaseApiController;
use App\Http\Requests\ClassProgress\ClassProgressIndexRequest;
use App\Http\Requests\ClassProgress\ClassProgressMetaRequest;
use App\Http\Requests\ClassProgress\ClassProgressStoreRequest;
use App\Http\Requests\ClassProgress\ClassProgressUpdateRequest;
use App\Http\Resources\ClassProgress\ClassProgressGroupCollection;
use App\Http\Resources\ClassProgress\ClassProgressReportResource;
use App\Http\Resources\ClassProgress\ClassProgressShowResource;
use App\Models\ClassProgressAttachment;
use App\Models\ClassProgressReport;
use App\Models\Configuration;
use App\Models\User;
use App\Services\ClassProgress\ClassProgressAttachmentService;
use App\Services\ClassProgress\ClassProgressMetaService;
use App\Services\ClassProgress\ClassProgressMutationService;
use App\Services\ClassProgress\ClassProgressQueryService;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Log;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Symfony\Component\HttpFoundation\Response;

class ClassProgressController extends BaseApiController
{
    public function __construct(
        private ClassProgressQueryService $queryService,
        private ClassProgressMutationService $mutationService,
        private ClassProgressMetaService $metaService,
        private ClassProgressAttachmentService $attachmentService
    ) {
        parent::__construct();
        $this->authorizeResource(ClassProgressReport::class, 'class_progress');
    }

    public function meta(ClassProgressMetaRequest $request): JsonResponse
    {
        return $this->respondSuccess(
            $this->buildMetaPayload(
                $request->validated('class_id'),
                (int) ($request->validated('sunday_count') ?? 12),
                $request->query('school_year'),
                $request->query('semester')
            ),
            'Progress metadata loaded.'
        );
    }

    /**
     * Legacy teacher portal URL for the weekly class progress submit page.
     */
    public function legacySubmitForm(ClassProgressMetaRequest $request): JsonResponse
    {
        $auth = $this->requireAuthenticatedUser($request->user());
        if ($auth instanceof JsonResponse) {
            return $auth;
        }

        $schoolYear = (string) (Configuration::getConfig('school_year') ?? '');
        $semester = (string) (Configuration::getConfig('semester') ?? '');
        $assignments = $this->queryService->teacherAssignments($auth, $schoolYear, $semester);

        $requestedClassId = (int) ($request->validated('class_id') ?? 0);
        $activeClassId = $requestedClassId > 0 ? $requestedClassId : (int) ($assignments[0]['class_id'] ?? 0);
        $activeAssignment = collect($assignments)->first(
            fn (array $assignment) => (int) ($assignment['class_id'] ?? 0) === $activeClassId
        ) ?? ($assignments[0] ?? []);
        $sundayCount = (int) ($request->validated('sunday_count') ?? 12);
        $payload = $this->buildMetaPayload($activeClassId > 0 ? $activeClassId : null, $sundayCount, $schoolYear, $semester);
        $payload['classes'] = $assignments;
        $payload['defaults'] = [
            'class_id' => $activeClassId > 0 ? $activeClassId : null,
            'class_section_id' => (int) ($activeAssignment['class_section_id'] ?? 0) ?: null,
            'school_year' => $schoolYear !== '' ? $schoolYear : null,
            'semester' => $semester !== '' ? $semester : null,
            'week_start' => $this->metaService->pickDefaultWeekStart($payload['sunday_options']),
        ];

        return $this->respondSuccess($payload, 'Progress metadata loaded.');
    }

    public function index(ClassProgressIndexRequest $request): JsonResponse
    {
        $auth = $this->requireAuthenticatedUser($request->user());
        if ($auth instanceof JsonResponse) {
            return $auth;
        }

        $filters = $request->validated();
        $meta = $this->queryService->meta($filters['school_year'] ?? null, $filters['semester'] ?? null);
        $filters['school_year'] = $filters['school_year'] ?? ($meta['school_year'] ?? null);
        $filters['semester'] = $filters['semester'] ?? ($meta['semester'] ?? null);
        $paginator = $this->queryService->listReports($auth, $filters);

        if (!empty($filters['group_by_week'])) {
            $grouped = ClassProgressGroupCollection::fromPaginator($paginator);
            return $this->respondSuccess($grouped, 'Progress reports retrieved.');
        }

        return $this->respondSuccess([
            'items' => ClassProgressReportResource::collection($paginator->items()),
            'meta' => $meta,
            'pagination' => [
                'current_page' => $paginator->currentPage(),
                'per_page' => $paginator->perPage(),
                'total' => $paginator->total(),
                'last_page' => $paginator->lastPage(),
            ],
        ], 'Progress reports retrieved.');
    }

    public function store(ClassProgressStoreRequest $request): JsonResponse
    {
        $auth = $this->requireAuthenticatedUser($request->user());
        if ($auth instanceof JsonResponse) {
            return $auth;
        }

        try {
            $filesBySubject = $request->filesBySubject();
            $reports = $this->mutationService->createReports($auth, $request->validated(), $filesBySubject);
        } catch (\InvalidArgumentException $e) {
            if ($e->getMessage() === 'CONFIRM_OVERWRITE') {
                return response()->json([
                    'status' => false,
                    'message' => 'A progress report already exists for this week. Resubmit with confirm_overwrite=true to replace it.',
                    'data' => ['requires_confirmation' => true],
                ], 409);
            }

            return $this->respondError($e->getMessage(), 422);
        } catch (\Throwable $e) {
            Log::error('Failed to create class progress reports.', [
                'error' => $e->getMessage(),
            ]);
            return $this->respondError('Unable to save progress reports.', 500);
        }

        return $this->respondCreated(ClassProgressReportResource::collection($reports), 'Progress reports saved.');
    }

    public function show(ClassProgressReport $class_progress): JsonResponse
    {
        $auth = $this->requireAuthenticatedUser($this->laravelRequest->user());
        if ($auth instanceof JsonResponse) {
            return $auth;
        }

        $weeklyReports = $this->queryService->weeklyReports($auth, $class_progress);

        return $this->respondSuccess(
            new ClassProgressShowResource([
                'report' => $class_progress,
                'weekly_reports' => $weeklyReports,
                'status_options' => $this->metaService->statusOptions(),
            ]),
            'Progress report retrieved.'
        );
    }

    public function update(ClassProgressUpdateRequest $request, ClassProgressReport $class_progress): JsonResponse
    {
        try {
            $updated = $this->mutationService->updateReport($class_progress, $request->validated(), $request->attachments());
        } catch (\InvalidArgumentException $e) {
            return $this->respondError($e->getMessage(), 422);
        } catch (\Throwable $e) {
            Log::error('Failed to update class progress report.', [
                'error' => $e->getMessage(),
            ]);
            return $this->respondError('Unable to update progress report.', 500);
        }

        return $this->respondSuccess(new ClassProgressReportResource($updated), 'Progress report updated.');
    }

    public function destroy(ClassProgressReport $class_progress): JsonResponse
    {
        try {
            $this->mutationService->deleteReport($class_progress);
        } catch (\Throwable $e) {
            Log::error('Failed to delete class progress report.', [
                'error' => $e->getMessage(),
            ]);
            return $this->respondError('Unable to delete progress report.', 500);
        }

        return $this->respondDeleted(null, 'Progress report deleted.');
    }

    public function downloadAttachment(int $attachment): BinaryFileResponse|JsonResponse
    {
        $record = ClassProgressAttachment::query()->find($attachment);
        if (!$record || !$record->file_path) {
            return $this->respondError('Attachment not found.', 404);
        }

        if ($record->report) {
            $this->authorize('view', $record->report);
        }

        $path = $this->attachmentService->resolvePath($record->file_path);
        if (!$path) {
            return $this->respondError('Attachment missing.', 404);
        }

        $downloadName = $record->original_name ?: basename($path);
        return response()->download($path, $downloadName);
    }

    public function downloadLegacyAttachment(ClassProgressReport $class_progress): BinaryFileResponse|JsonResponse
    {
        $this->authorize('view', $class_progress);

        if (!$class_progress->attachment_path) {
            return $this->respondError('Attachment not found.', 404);
        }

        $path = $this->attachmentService->resolvePath($class_progress->attachment_path);
        if (!$path) {
            return $this->respondError('Attachment missing.', 404);
        }

        return response()->download($path, basename($path));
    }

    /**
     * @param  mixed  $user
     * @return User|JsonResponse
     */
    private function requireAuthenticatedUser($user): User|JsonResponse
    {
        if (!$user instanceof User) {
            $user = auth()->user();
        }

        if (!$user instanceof User) {
            $user = $this->laravelRequest->user();
        }

        if (!$user instanceof User) {
            return $this->respondError('Unauthorized.', Response::HTTP_UNAUTHORIZED);
        }

        return $user;
    }

    private function buildMetaPayload(?int $classId, int $sundayCount, ?string $schoolYear = null, ?string $semester = null): array
    {
        $meta = $this->queryService->meta($schoolYear, $semester);

        return [
            'subject_sections' => $this->metaService->subjectSections(),
            'status_options' => $this->metaService->statusOptions(),
            'sunday_options' => $this->metaService->sundayOptionsAlignedWithCi($sundayCount),
            'curriculum' => $this->metaService->curriculumOptions($classId, $meta['school_year'] ?? null),
            'meta' => $meta,
        ];
    }
}
