<?php

namespace App\Http\Controllers\Admin\Manage;

use App\Http\Controllers\Controller;
use App\Http\Requests\Admin\Manage\RejectCourseRegistrationRequest;
use App\Http\Requests\Admin\Manage\SaveCourseRegistrationRequest;
use App\Http\Requests\Admin\Manage\SignCourseRegistrationRequest;
use App\Http\Requests\PaginatedRequest;
use App\Models\Course;
use App\Models\CourseRegistrationSubmission;
use App\Models\Student;
use App\Services\Admin\Manage\CourseRegistrationService;
use App\Services\Admin\Master\AcademicTermService;
use Illuminate\Http\RedirectResponse;
use Inertia\Inertia;
use Inertia\Response;

class CourseRegistrationController extends Controller
{
    public function __construct(
        private readonly CourseRegistrationService $service,
        private readonly AcademicTermService $academicTermService,
    ) {}

    public function index(PaginatedRequest $request): Response|RedirectResponse
    {
        $user = auth()->user();

        if ($user->hasRole('mahasiswa')) {
            return to_route('admin.manage.course-registrations.show', $user->student->id);
        }

        $isKaprodi = $user->hasRole('kaprodi');

        return Inertia::render('admin/manage/course-registrations/index', [
            'departments' => $this->service->departmentSummary(),
            'registrations' => $this->service->paginated(
                ...$request->validatedWithDefaults(),
                departmentId: $request->validated('department_id'),
                advisorLecturerId: ! $isKaprodi && $user->hasRole('dosen') ? $user->lecturer?->id : null,
                ledDepartmentIds: $isKaprodi ? $user->ledDepartmentIds() : null,
            ),
            'filters' => $request->only(['department_id']),
        ]);
    }

    public function show(Student $student): Response
    {
        $user = auth()->user();
        $isStudent = $user->hasRole('mahasiswa');

        abort_if($isStudent && $user->student->id !== $student->id, 403);
        abort_if(! $isStudent && ! $user->canAccessCourseRegistrationOf($student), 403);

        $backHref = $isStudent
            ? null
            : route('admin.manage.course-registrations.index');

        $canReview = ! $isStudent
            && $user->can('approve-course-registrations')
            && $user->canReviewCourseRegistrationOf($student);

        $canSignAsKaprodi = $user->isKaprodiOf($student);
        $canSignAsAdvisor = $user->isAdvisorOf($student);

        $activeTerm = $this->academicTermService->getActive();
        $allCourseClasses = $activeTerm
            ? $this->service->availableCourseClasses($student->department_id, $activeTerm->id)
            : collect();

        $departmentCourses = $this->service->departmentCourses($student->department_id);

        $semesters = $departmentCourses
            ->map(fn (Course $course) => $course->semester_number)
            ->unique()
            ->sort()
            ->values();

        $submissions = $activeTerm
            ? $semesters->mapWithKeys(fn (?int $semesterNumber) => [
                CourseRegistrationSubmission::semesterKey($semesterNumber) => $this->service->buildSubmissionPayload(
                    $student,
                    $activeTerm,
                    $semesterNumber,
                    $departmentCourses,
                    $allCourseClasses,
                ),
            ])
            : collect();

        return Inertia::render('admin/manage/course-registrations/show', [
            'submissions' => $submissions,
            'semesters' => $semesters->values(),
            'openSemesters' => $activeTerm?->open_semesters ?? [],
            'studentCurrentSemester' => $student->current_semester,
            'hasActiveTerm' => $activeTerm !== null,
            'backHref' => $backHref,
            'canReview' => $canReview,
            'canSignAsKaprodi' => $canSignAsKaprodi,
            'canSignAsAdvisor' => $canSignAsAdvisor,
        ]);
    }

    public function save(Student $student, string $semester, SaveCourseRegistrationRequest $request): RedirectResponse
    {
        $semesterNumber = CourseRegistrationSubmission::parseSemesterKey($semester);

        $activeTerm = $this->academicTermService->getActive();

        abort_if($activeTerm === null, 422);

        $selectableIds = $this->service->selectableCourseClassIds(
            $student->department_id,
            $activeTerm->id,
            $semesterNumber,
            $activeTerm->open_semesters ?? [],
            $student->current_semester,
        );

        $selectedIds = array_values(array_intersect(
            $request->validated('course_class_ids') ?? [],
            $selectableIds,
        ));

        $submission = $this->service->findOrCreateForStudent($student, $activeTerm, $semesterNumber);

        $this->service->saveRegistrations(
            $submission,
            $selectedIds,
            $activeTerm->id,
            $student->id,
            $request->file('signature'),
        );

        Inertia::flash('toast', ['type' => 'success', 'message' => 'KRS berhasil disimpan.']);

        return to_route('admin.manage.course-registrations.show', $student->id);
    }

    public function signAsKaprodi(Student $student, string $semester, SignCourseRegistrationRequest $request): RedirectResponse
    {
        abort_unless(auth()->user()->isKaprodiOf($student), 403);

        $submission = $this->service->findOrCreateForSemester($student, $semester);

        $this->service->signAsKaprodi($submission, $request->file('signature'));

        Inertia::flash('toast', ['type' => 'success', 'message' => 'Tanda tangan berhasil disimpan.']);

        return to_route('admin.manage.course-registrations.show', $student->id);
    }

    public function signAsAdvisor(Student $student, string $semester, SignCourseRegistrationRequest $request): RedirectResponse
    {
        abort_unless(auth()->user()->isAdvisorOf($student), 403);

        $submission = $this->service->findOrCreateForSemester($student, $semester);

        $this->service->signAsAdvisor($submission, $request->file('signature'));

        Inertia::flash('toast', ['type' => 'success', 'message' => 'Tanda tangan berhasil disimpan.']);

        return to_route('admin.manage.course-registrations.show', $student->id);
    }

    public function approve(CourseRegistrationSubmission $submission): RedirectResponse
    {
        abort_unless(auth()->user()->canReviewCourseRegistrationOf($submission->student), 403);

        $this->service->approve($submission);

        return Inertia::flash('toast', ['type' => 'success', 'message' => 'KRS berhasil disetujui.'])->back();
    }

    public function reject(RejectCourseRegistrationRequest $request, CourseRegistrationSubmission $submission): RedirectResponse
    {
        abort_unless(auth()->user()->canReviewCourseRegistrationOf($submission->student), 403);

        $this->service->reject($submission, $request->validated('reason'));

        return Inertia::flash('toast', ['type' => 'success', 'message' => 'KRS berhasil ditolak.'])->back();
    }
}
