<?php

namespace App\Http\Controllers\Api\ClassProgress;

use App\Http\Controllers\Api\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\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;

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
    {
        $classId = $request->validated('class_id');
        $sundayCount = (int) ($request->validated('sunday_count') ?? 12);

        $payload = [
            'subject_sections' => $this->metaService->subjectSections(),
            'status_options' => $this->metaService->statusOptions(),
            'sunday_options' => $this->metaService->sundayOptions($sundayCount),
            'curriculum' => $this->metaService->curriculumOptions($classId ? (int) $classId : null),
        ];

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

    public function index(ClassProgressIndexRequest $request): JsonResponse
    {
        $filters = $request->validated();
        $paginator = $this->queryService->listReports($request->user(), $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()),
            '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
    {
        try {
            $filesBySubject = $request->filesBySubject();
            $reports = $this->mutationService->createReports($request->user(), $request->validated(), $filesBySubject);
        } catch (\InvalidArgumentException $e) {
            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
    {
        $weeklyReports = $this->queryService->weeklyReports($this->laravelRequest->user(), $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));
    }
}
