<?php

namespace App\Http\Controllers\School;

use App\Http\Controllers\Controller;
use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Http\Response as HttpResponse;
use Illuminate\Support\Facades\DB;
use Inertia\Inertia;
use Inertia\Response;

class GradeController extends Controller
{
    public function index(Request $request): Response
    {
        $schoolId = $this->currentSchoolId($request);

        $grades = $schoolId
            ? DB::table('grades')
                ->join('students', 'students.id', '=', 'grades.student_id')
                ->leftJoin('subjects', 'subjects.id', '=', 'grades.subject_id')
                ->leftJoin('classrooms', 'classrooms.id', '=', 'grades.classroom_id')
                ->leftJoin('teachers', 'teachers.id', '=', 'grades.teacher_id')
                ->where('grades.school_id', $schoolId)
                ->select([
                    'grades.id',
                    'students.first_name',
                    'students.last_name',
                    'subjects.name as subject_name',
                    'classrooms.name as classroom_name',
                    'teachers.first_name as teacher_first_name',
                    'teachers.last_name as teacher_last_name',
                    'grades.score',
                    'grades.max_score',
                    'grades.status',
                    'grades.description',
                    'grades.updated_at',
                ])
                ->latest('grades.updated_at')
                ->limit(200)
                ->get()
            : collect();

        return Inertia::render('School/Grades', [
            'grades' => $grades->map(fn ($grade): array => [
                'id' => (int) $grade->id,
                'student' => trim($grade->first_name.' '.$grade->last_name),
                'subject' => $grade->subject_name ?: '—',
                'classroom' => $grade->classroom_name ?: '—',
                'teacher' => trim(($grade->teacher_first_name ?? '').' '.($grade->teacher_last_name ?? '')) ?: '—',
                'score' => (float) $grade->score,
                'maxScore' => (float) $grade->max_score,
                'status' => $grade->status,
                'description' => $grade->description ?? '',
                'updatedAt' => $this->jalaliDate((string) $grade->updated_at, true),
            ])->values(),
        ]);
    }

    public function approve(Request $request, int $id): RedirectResponse
    {
        $schoolId = $this->currentSchoolId($request);

        $grade = DB::table('grades')->where('school_id', $schoolId)->where('id', $id)->first();
        abort_unless($grade, 404);

        DB::table('grades')->where('id', $id)->update([
            'status' => 'approved',
            'updated_at' => now(),
        ]);

        $this->auditGrade($request, $id, 'grade_approved', ['score' => $grade->score, 'status_before' => $grade->status]);

        return back()->with('success', 'نمره تایید شد.');
    }

    public function reject(Request $request, int $id): RedirectResponse
    {
        $schoolId = $this->currentSchoolId($request);

        $grade = DB::table('grades')->where('school_id', $schoolId)->where('id', $id)->first();
        abort_unless($grade, 404);

        $data = $request->validate(['reason' => ['nullable', 'string', 'max:500']]);

        DB::table('grades')->where('id', $id)->update([
            'status' => 'rejected',
            'updated_at' => now(),
        ]);

        $this->auditGrade($request, $id, 'grade_rejected', [
            'score' => $grade->score,
            'reason' => $data['reason'] ?? null,
        ]);

        return back()->with('success', 'نمره رد شد.');
    }

    public function reportCard(Request $request): Response
    {
        $schoolId = $this->currentSchoolId($request);

        $students = $schoolId
            ? DB::table('students')
                ->where('school_id', $schoolId)
                ->where('status', 'active')
                ->orderBy('last_name')
                ->get(['id', 'first_name', 'last_name', 'student_code'])
            : collect();

        $studentId = $request->integer('student_id') ?: null;
        $card = [];

        if ($studentId && $schoolId) {
            $studentOk = DB::table('students')->where('school_id', $schoolId)->where('id', $studentId)->exists();
            if ($studentOk) {
                $rows = DB::table('grades')
                    ->leftJoin('subjects', 'subjects.id', '=', 'grades.subject_id')
                    ->leftJoin('classrooms', 'classrooms.id', '=', 'grades.classroom_id')
                    ->where('grades.school_id', $schoolId)
                    ->where('grades.student_id', $studentId)
                    ->select([
                        'subjects.name as subject_name',
                        'classrooms.name as classroom_name',
                        'grades.score',
                        'grades.max_score',
                        'grades.status',
                        'grades.description',
                    ])
                    ->orderBy('subjects.name')
                    ->get();

                $card = $rows->map(fn ($row): array => [
                    'subject' => $row->subject_name ?: '—',
                    'classroom' => $row->classroom_name ?: '—',
                    'score' => (float) $row->score,
                    'maxScore' => (float) $row->max_score,
                    'status' => $row->status,
                    'description' => $row->description ?? '',
                ])->all();
            }
        }

        return Inertia::render('School/ReportCard', [
            'students' => $students->map(fn ($student): array => [
                'value' => $student->id,
                'label' => trim($student->first_name.' '.$student->last_name).' - '.$student->student_code,
            ])->values(),
            'selectedStudentId' => $studentId,
            'card' => $card,
        ]);
    }

    public function reportCardPdf(Request $request): HttpResponse|\Illuminate\Http\Response
    {
        $schoolId = $this->currentSchoolId($request);
        $studentId = $request->integer('student_id');

        abort_unless($schoolId && $studentId, 400);

        $student = DB::table('students')
            ->where('school_id', $schoolId)
            ->where('id', $studentId)
            ->first();

        abort_unless($student, 404);

        $school = DB::table('schools')->where('id', $schoolId)->first();

        $grades = DB::table('grades')
            ->leftJoin('subjects', 'subjects.id', '=', 'grades.subject_id')
            ->leftJoin('classrooms', 'classrooms.id', '=', 'grades.classroom_id')
            ->where('grades.school_id', $schoolId)
            ->where('grades.student_id', $studentId)
            ->select([
                'subjects.name as subject_name',
                'classrooms.name as classroom_name',
                'grades.score',
                'grades.max_score',
                'grades.status',
                'grades.description',
            ])
            ->orderBy('subjects.name')
            ->get();

        $average = $grades->count() > 0
            ? round($grades->avg(fn ($g) => ($g->max_score > 0 ? $g->score / $g->max_score * 20 : 0)), 2)
            : null;

        $pdf = Pdf::loadView('pdf.report-card', [
            'student' => $student,
            'school' => $school,
            'grades' => $grades,
            'average' => $average,
            'jalaliDate' => fn ($d) => $this->jalaliDate((string) $d),
        ])->setPaper('a4', 'portrait');

        $name = 'كارنامه-'.$student->first_name.'-'.$student->last_name.'.pdf';

        return $pdf->stream($name);
    }

    private function auditGrade(Request $request, int $gradeId, string $action, array $meta): void
    {
        try {
            DB::table('audit_logs')->insert([
                'school_id' => $this->currentSchoolId($request),
                'user_id' => $request->user()?->id,
                'action' => $action,
                'entity_type' => 'grade',
                'entity_id' => $gradeId,
                'old_value' => json_encode($meta, JSON_UNESCAPED_UNICODE),
                'ip_address' => $request->ip(),
                'created_at' => now(),
            ]);
        } catch (\Throwable) {
        }
    }
}
