<?php

namespace App\Http\Controllers\Teacher;

use App\Http\Controllers\Controller;
use App\Http\Requests\Grade\StoreGradeRequest;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
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('grade_change_logs', 'grade_change_logs.grade_id', '=', 'grades.id')
                ->leftJoin('users as changed_by', 'changed_by.id', '=', 'grade_change_logs.changed_by')
                ->where('grades.school_id', $schoolId)
                ->select([
                    'grades.id',
                    'grades.status',
                    'students.first_name',
                    'students.last_name',
                    'subjects.name as subject_name',
                    'grades.score',
                    'grades.max_score',
                    'grade_change_logs.old_score',
                    'grade_change_logs.new_score',
                    'grade_change_logs.created_at as changed_at',
                    'changed_by.first_name as changer_first_name',
                    'changed_by.last_name as changer_last_name',
                ])
                ->latest('grades.updated_at')
                ->limit(50)
                ->get()
            : collect();

        return Inertia::render('Grades/GradeTable', [
            'students' => $this->studentOptions((int) ($schoolId ?? 0)),
            'classes' => $this->classroomOptions((int) ($schoolId ?? 0)),
            'subjects' => $this->subjectOptions((int) ($schoolId ?? 0)),
            'grades' => $grades->map(fn ($grade): array => [
                'id' => (int) $grade->id,
                'student' => trim($grade->first_name.' '.$grade->last_name),
                'subject' => $grade->subject_name ?: '—',
                'score' => (float) $grade->score,
                'maxScore' => (float) $grade->max_score,
                'statusKey' => $grade->status,
                'status' => $this->gradeStatusLabel($grade->status),
                'oldScore' => $grade->old_score !== null ? (float) $grade->old_score : null,
                'newScore' => $grade->new_score !== null ? (float) $grade->new_score : null,
                'changedBy' => trim(($grade->changer_first_name ?? '').' '.($grade->changer_last_name ?? '')) ?: '—',
                'changedAt' => $grade->changed_at ? $this->jalaliDate($grade->changed_at, true) : 'بدون تغییر',
            ])->values(),
        ]);
    }

    public function store(StoreGradeRequest $request): RedirectResponse
    {
        $schoolId = $this->currentSchoolId($request);

        abort_unless($schoolId, 422, 'مدرسه مشخص نیست.');

        $data = $request->validated();

        $studentOk = DB::table('students')->where('school_id', $schoolId)->where('id', $data['student_id'])->exists();
        $classOk = DB::table('classrooms')->where('school_id', $schoolId)->where('id', $data['classroom_id'])->exists();
        $subjectOk = DB::table('subjects')->where('school_id', $schoolId)->where('id', $data['subject_id'])->exists();

        if (! $studentOk || ! $classOk || ! $subjectOk) {
            return back()->withErrors(['student_id' => 'دانش‌آموز، کلاس یا درس برای این مدرسه معتبر نیست.'])->withInput();
        }

        $teacherId = DB::table('teachers')
            ->where('school_id', $schoolId)
            ->where('user_id', $request->user()?->id)
            ->value('id');

        DB::transaction(function () use ($request, $schoolId, $data, $teacherId): void {
            $gradeId = DB::table('grades')->insertGetId([
                'school_id' => $schoolId,
                'student_id' => $data['student_id'],
                'classroom_id' => $data['classroom_id'],
                'subject_id' => $data['subject_id'],
                'teacher_id' => $teacherId,
                'exam_id' => $data['exam_id'] ?? null,
                'score' => $data['score'],
                'max_score' => $data['max_score'] ?? 20,
                'status' => 'submitted',
                'description' => $data['description'] ?? null,
                'created_by' => $request->user()?->id,
                'created_at' => now(),
                'updated_at' => now(),
            ]);

            DB::table('grade_change_logs')->insert([
                'school_id' => $schoolId,
                'grade_id' => $gradeId,
                'student_id' => $data['student_id'],
                'changed_by' => $request->user()?->id,
                'old_score' => null,
                'new_score' => $data['score'],
                'reason' => 'ثبت اولیه نمره',
                'ip_address' => $request->ip(),
                'created_at' => now(),
            ]);
        });

        return redirect()->route('teacher.grades')->with('success', 'نمره ثبت شد و audit log ساخته شد.');
    }

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

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

        if (! in_array($grade->status, ['draft', 'submitted'])) {
            return back()->withErrors(['score' => 'نمره تایید شده قابل ویرایش نیست.']);
        }

        $data = $request->validate([
            'score' => ['required', 'numeric', 'min:0'],
            'max_score' => ['required', 'numeric', 'min:1'],
            'reason' => ['nullable', 'string', 'max:500'],
        ]);

        if ((float) $data['score'] > (float) $data['max_score']) {
            return back()->withErrors(['score' => 'نمره نمی‌تواند از نمره کل بیشتر باشد.']);
        }

        DB::transaction(function () use ($request, $schoolId, $id, $grade, $data): void {
            DB::table('grades')->where('id', $id)->update([
                'score' => $data['score'],
                'max_score' => $data['max_score'],
                'status' => 'submitted',
                'updated_at' => now(),
            ]);

            DB::table('grade_change_logs')->insert([
                'school_id' => $schoolId,
                'grade_id' => $id,
                'student_id' => $grade->student_id,
                'changed_by' => $request->user()?->id,
                'old_score' => $grade->score,
                'new_score' => $data['score'],
                'reason' => $data['reason'] ?? 'ویرایش نمره',
                'ip_address' => $request->ip(),
                'created_at' => now(),
            ]);
        });

        return redirect()->route('teacher.grades')->with('success', 'نمره ویرایش شد.');
    }

    private function gradeStatusLabel(string $status): string
    {
        return match ($status) {
            'draft' => 'پیش‌نویس',
            'submitted' => 'ارسال شده',
            'approved' => 'تایید شده',
            'rejected' => 'رد شده',
            default => $status,
        };
    }

    private function studentOptions(int $schoolId): array
    {
        if (! $schoolId) {
            return [];
        }

        return DB::table('students')
            ->where('school_id', $schoolId)
            ->where('status', 'active')
            ->orderBy('last_name')
            ->get(['id', 'first_name', 'last_name', 'student_code'])
            ->map(fn ($student): array => ['value' => $student->id, 'label' => trim($student->first_name.' '.$student->last_name).' - '.$student->student_code])
            ->values()
            ->all();
    }

    private function classroomOptions(int $schoolId): array
    {
        if (! $schoolId) {
            return [];
        }

        return DB::table('classrooms')
            ->where('school_id', $schoolId)
            ->where('status', 'active')
            ->orderBy('name')
            ->get(['id', 'name'])
            ->map(fn ($classroom): array => ['value' => $classroom->id, 'label' => $classroom->name])
            ->values()
            ->all();
    }

    private function subjectOptions(int $schoolId): array
    {
        if (! $schoolId) {
            return [];
        }

        return DB::table('subjects')
            ->where('school_id', $schoolId)
            ->where('status', 'active')
            ->orderBy('name')
            ->get(['id', 'name'])
            ->map(fn ($subject): array => ['value' => $subject->id, 'label' => $subject->name])
            ->values()
            ->all();
    }
}
