<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\ActivityLog;
use App\Models\Evaluation;
use App\Models\EvaluationResult;
use App\Models\EvaluationStudentNote;
use App\Models\SchoolClass;
use App\Models\Student;
use App\Models\Subject;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class EvaluationController extends Controller
{
    private array $monthsFa = [
        1 => 'حمل', 2 => 'ثور', 3 => 'جوزا', 4 => 'سرطان', 5 => 'اسد', 6 => 'سنبله',
        7 => 'میزان', 8 => 'عقرب', 9 => 'قوس', 10 => 'جدی', 11 => 'دلو', 12 => 'حوت',
    ];
    private array $monthsEn = [
        1 => 'Hamal', 2 => 'Sawr', 3 => 'Jawza', 4 => 'Saratan', 5 => 'Asad', 6 => 'Sonbola',
        7 => 'Mizan', 8 => 'Aqrab', 9 => 'Qaws', 10 => 'Jadi', 11 => 'Dalw', 12 => 'Hoot',
    ];

    private function isAdmin(Request $request): bool
    {
        $u = $request->user();
        return $u && ($u->role === 'super-admin' || $u->role === 'admin');
    }

    /* ── Class list with completion + overall % ───────────────────── */
    public function classes(Request $request)
    {
        $branchId = $request->header('X-Branch-Id') ?: $request->query('branch_id');

        $classes = SchoolClass::query()
            ->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
            ->orderBy('level')->orderBy('section')->get();

        $evals = Evaluation::query()
            ->when($branchId, fn ($q) => $q->where('branch_id', $branchId))
            ->get(['id', 'class_id', 'month_shamsi', 'status', 'class_avg']);

        $counts = Student::where('status', 'active')
            ->select('class_id', DB::raw('count(*) as c'))->groupBy('class_id')->pluck('c', 'class_id');

        $rows = $classes->map(function ($c) use ($evals, $counts) {
            $ce = $evals->where('class_id', $c->id)->values();
            $completed = $ce->where('status', 'completed');
            $avgs = $completed->whereNotNull('class_avg')->pluck('class_avg');
            return [
                'id' => $c->id,
                'name' => $c->name,
                'name_fa' => $c->name_fa,
                'name_en' => $c->name_en,
                'level' => $c->level,
                'section' => $c->section,
                'shift' => $c->shift,
                'student_count' => (int) ($counts[$c->id] ?? 0),
                'overall_avg' => $avgs->count() ? round($avgs->avg(), 1) : null,
                'months' => $ce->map(fn ($e) => ['month' => $e->month_shamsi, 'status' => $e->status, 'avg' => $e->class_avg])->values(),
                'completed' => $completed->count(),
                'total_evals' => $ce->count(),
                'has_active' => $ce->where('status', 'in_progress')->count() > 0,
            ];
        });

        return response()->json(['data' => $rows]);
    }

    /* ── Class dashboard (months) ─────────────────────────────────── */
    public function classMonths(Request $request, $classId)
    {
        $class = SchoolClass::findOrFail($classId);
        $studentCount = Student::where('class_id', $classId)->where('status', 'active')->count();

        $evaluations = Evaluation::where('class_id', $classId)
            ->orderBy('month_shamsi')
            ->get()
            ->map(function ($e) use ($studentCount) {
                $filled = EvaluationResult::where('evaluation_id', $e->id)->whereNotNull('marks')
                    ->distinct('student_id')->count('student_id');
                return array_merge($e->toArray(), [
                    'filled_count' => $filled,
                    'total_students' => $studentCount,
                    'month_name_en' => $this->monthsEn[$e->month_shamsi] ?? '',
                    'locked_for_role' => $e->status === 'completed',
                ]);
            });

        return response()->json([
            'cls' => array_merge($class->toArray(), ['student_count' => $studentCount]),
            'evaluations' => $evaluations,
            'is_admin' => $this->isAdmin($request),
        ]);
    }

    /* ── Legacy flat list (kept for trash/other callers) ──────────── */
    public function index(Request $request)
    {
        $branchId = $request->header('X-Branch-Id') ?: $request->query('branch_id');

        $rows = Evaluation::query()
            ->when($branchId, fn ($q) => $q->where('evaluations.branch_id', $branchId))
            ->when($request->filled('class_id'), fn ($q) => $q->where('evaluations.class_id', $request->query('class_id')))
            ->when($request->filled('status'), fn ($q) => $q->where('evaluations.status', $request->query('status')))
            ->leftJoin('school_classes', 'evaluations.class_id', '=', 'school_classes.id')
            ->select('evaluations.*', 'school_classes.name as class_name', 'school_classes.name_fa as class_name_fa', 'school_classes.name_en as class_name_en')
            ->selectSub(fn ($q) => $q->from('students')->whereColumn('students.class_id', 'evaluations.class_id')->selectRaw('count(*)'), 'total_students')
            ->selectSub(fn ($q) => $q->from('evaluation_results')->whereColumn('evaluation_results.evaluation_id', 'evaluations.id')->whereNotNull('marks')->selectRaw('count(distinct student_id)'), 'filled_count')
            ->orderByDesc('evaluations.created_at')
            ->get();

        return response()->json(['data' => $rows]);
    }

    /* ── Full evaluation form payload ─────────────────────────────── */
    public function show(Request $request, Evaluation $evaluation)
    {
        $evaluation->loadMissing('schoolClass');

        $students = Student::where('class_id', $evaluation->class_id)->where('status', 'active')
            ->orderBy('roll_number')->orderBy('first_name')->get();
        $subjects = Subject::orderBy('sort_order')->orderBy('id')->get();
        $results = EvaluationResult::where('evaluation_id', $evaluation->id)->get();
        $studentNotes = EvaluationStudentNote::where('evaluation_id', $evaluation->id)->get(['student_id', 'note', 'is_critical', 'discipline']);

        // Attendance % per student for this evaluation's month (drives the 15% component).
        $attPct = \App\Models\Attendance::where('person_type', 'student')
            ->whereIn('person_id', $students->pluck('id'))->get()->groupBy('person_id')
            ->map(function ($g) {
                $present = $g->whereIn('status', ['present', 'late', 'activity'])->count();
                return $g->count() ? round($present / $g->count() * 100) : null;
            });

        // Every evaluation of this class → month tabs.
        $allClassEvals = Evaluation::where('class_id', $evaluation->class_id)
            ->orderBy('month_shamsi')->get(['id', 'month_shamsi', 'status', 'class_avg']);

        $prevEvals = $allClassEvals->where('month_shamsi', '<', $evaluation->month_shamsi)
            ->where('id', '!=', $evaluation->id)->values();
        $prevIds = $prevEvals->pluck('id');

        $historyResults = $prevIds->isEmpty() ? [] : EvaluationResult::whereIn('evaluation_id', $prevIds)
            ->whereNotNull('marks')
            ->join('evaluations', 'evaluation_results.evaluation_id', '=', 'evaluations.id')
            ->get(['student_id', 'subject_id', 'marks', 'evaluation_results.note', 'evaluations.month_shamsi']);

        $historyStudentNotes = $prevIds->isEmpty() ? [] : EvaluationStudentNote::whereIn('evaluation_id', $prevIds)
            ->join('evaluations', 'evaluation_student_notes.evaluation_id', '=', 'evaluations.id')
            ->get(['student_id', 'evaluation_student_notes.note', 'is_critical', 'evaluations.month_shamsi']);

        $isAdmin = $this->isAdmin($request);

        return response()->json(array_merge($evaluation->toArray(), [
            'class_name' => $evaluation->schoolClass?->name,
            'class_name_fa' => $evaluation->schoolClass?->name_fa,
            'class_name_en' => $evaluation->schoolClass?->name_en,
            'students' => $students,
            'subjects' => $subjects,
            'results' => $results,
            'studentNotes' => $studentNotes,
            'attendancePct' => $attPct,
            'weights' => ['academic' => 70, 'discipline' => 15, 'attendance' => 15],
            'allClassEvals' => $allClassEvals,
            'prevEvals' => $prevEvals,
            'historyResults' => $historyResults,
            'historyStudentNotes' => $historyStudentNotes,
            'is_admin' => $isAdmin,
            // A completed month is read-only unless you are an admin.
            'locked' => $evaluation->status === 'completed' && !$isAdmin,
        ]));
    }

    public function store(Request $request)
    {
        $data = $request->validate([
            'class_id' => ['required', 'exists:school_classes,id'],
            'month_shamsi' => ['required', 'integer', 'between:1,12'],
            'year_shamsi' => ['nullable', 'integer'],
            'evaluator_name' => ['nullable', 'string'],
            'title_fa' => ['nullable', 'string'],
            'title_en' => ['nullable', 'string'],
        ]);

        // One evaluation per class+month.
        $existing = Evaluation::where('class_id', $data['class_id'])->where('month_shamsi', $data['month_shamsi'])->first();
        if ($existing) {
            return response()->json(['data' => $existing, 'id' => $existing->id, 'existing' => true]);
        }

        $monthFa = $this->monthsFa[$data['month_shamsi']] ?? '';
        $year = $data['year_shamsi'] ?? 1403;

        $evaluation = Evaluation::create([
            'branch_id' => $request->header('X-Branch-Id'),
            'class_id' => $data['class_id'],
            'month_shamsi' => $data['month_shamsi'],
            'month_name_fa' => $monthFa,
            'year_shamsi' => $year,
            'evaluator_name' => $data['evaluator_name'] ?? $request->user()?->name,
            'title_fa' => $data['title_fa'] ?? "ارزیابی ماه {$monthFa} {$year}",
            'title_en' => $data['title_en'] ?? "Month {$monthFa} Evaluation {$year}",
            'status' => 'in_progress',
        ]);
        ActivityLog::record('create', 'evaluation', "Created evaluation #{$evaluation->id}", $evaluation);

        return response()->json(['data' => $evaluation, 'id' => $evaluation->id, 'success' => true], 201);
    }

    // Single-mark autosave — the form saves each score as you type (debounced).
    public function saveResult(Request $request, Evaluation $evaluation)
    {
        $r = $request->validate([
            'student_id' => ['required', 'integer'],
            'subject_id' => ['required', 'integer'],
            'marks' => ['nullable', 'numeric', 'between:0,100'],
            'note' => ['nullable', 'string'],
        ]);

        if ($r['marks'] === null || $r['marks'] === '') {
            EvaluationResult::where('evaluation_id', $evaluation->id)
                ->where('student_id', $r['student_id'])->where('subject_id', $r['subject_id'])->delete();
        } else {
            EvaluationResult::updateOrCreate(
                ['evaluation_id' => $evaluation->id, 'student_id' => $r['student_id'], 'subject_id' => $r['subject_id']],
                ['marks' => $r['marks'], 'max_marks' => 100, 'note' => $r['note'] ?? null],
            );
        }
        if ($evaluation->status === 'draft') {
            $evaluation->update(['status' => 'in_progress']);
        }
        $this->recomputeAvg($evaluation);

        return response()->json(['success' => true, 'class_avg' => $evaluation->fresh()->class_avg]);
    }

    // Bulk upsert (used by the Save button as a safety net).
    public function saveResults(Request $request, Evaluation $evaluation)
    {
        $payload = $request->validate([
            'results' => ['required', 'array'],
            'results.*.student_id' => ['required', 'integer'],
            'results.*.subject_id' => ['required', 'integer'],
            'results.*.marks' => ['nullable', 'numeric'],
            'results.*.note' => ['nullable', 'string'],
        ]);

        DB::transaction(function () use ($payload, $evaluation) {
            foreach ($payload['results'] as $r) {
                EvaluationResult::updateOrCreate(
                    ['evaluation_id' => $evaluation->id, 'student_id' => $r['student_id'], 'subject_id' => $r['subject_id']],
                    ['marks' => $r['marks'] ?? null, 'max_marks' => 100, 'note' => $r['note'] ?? null],
                );
            }
            if ($evaluation->status === 'draft') {
                $evaluation->update(['status' => 'in_progress']);
            }
        });
        $this->recomputeAvg($evaluation);
        ActivityLog::record('update', 'evaluation', "Saved marks for evaluation #{$evaluation->id}", $evaluation);

        return response()->json(['success' => true, 'class_avg' => $evaluation->fresh()->class_avg]);
    }

    public function setStatus(Request $request, Evaluation $evaluation)
    {
        $data = $request->validate(['status' => ['required', 'in:draft,in_progress,completed,published']]);
        $evaluation->update(['status' => $data['status']]);
        $this->recomputeAvg($evaluation);
        ActivityLog::record('update', 'evaluation', "Evaluation #{$evaluation->id} -> {$data['status']}", $evaluation);

        return response()->json(['success' => true]);
    }

    public function saveNote(Request $request, Evaluation $evaluation)
    {
        $evaluation->update(['evaluator_note' => $request->input('note', '')]);

        return response()->json(['success' => true]);
    }

    public function saveStudentNote(Request $request, Evaluation $evaluation, $studentId)
    {
        $payload = ['note' => $request->input('note', ''), 'is_critical' => $request->boolean('is_critical')];
        if ($request->has('discipline')) {
            $payload['discipline'] = $request->input('discipline');
        }
        EvaluationStudentNote::updateOrCreate(
            ['evaluation_id' => $evaluation->id, 'student_id' => $studentId],
            $payload,
        );

        return response()->json(['success' => true]);
    }

    /* ── Per-student summary (student & parent pages) ─────────────── */
    public function studentSummary($studentId)
    {
        $student = Student::findOrFail($studentId);
        $subjects = Subject::orderBy('sort_order')->orderBy('id')->get(['id', 'name', 'name_fa', 'name_en']);

        $evals = Evaluation::where('class_id', $student->class_id)
            ->where('status', 'completed')->orderBy('month_shamsi')->get();

        $months = [];
        foreach ($evals as $ev) {
            $res = EvaluationResult::where('evaluation_id', $ev->id)->where('student_id', $studentId)
                ->whereNotNull('marks')->get(['subject_id', 'marks', 'note']);
            if ($res->isEmpty()) {
                continue;
            }
            $note = EvaluationStudentNote::where('evaluation_id', $ev->id)->where('student_id', $studentId)->first();
            $months[] = [
                'month' => $ev->month_shamsi,
                'month_name_fa' => $this->monthsFa[$ev->month_shamsi] ?? '',
                'month_name_en' => $this->monthsEn[$ev->month_shamsi] ?? '',
                'avg' => round($res->avg('marks'), 1),
                'subjects' => $res->mapWithKeys(fn ($r) => [$r->subject_id => ['marks' => (float) $r->marks, 'note' => $r->note]]),
                'note' => $note?->note,
                'is_critical' => (bool) $note?->is_critical,
            ];
        }

        $avgs = collect($months)->pluck('avg');
        $overall = $avgs->count() ? round($avgs->avg(), 1) : null;

        // Class rank in the latest completed evaluation.
        $rank = null;
        $classSize = null;
        if ($evals->count()) {
            $latest = $evals->last();
            $classAvgs = EvaluationResult::where('evaluation_id', $latest->id)->whereNotNull('marks')
                ->select('student_id', DB::raw('AVG(marks) as a'))->groupBy('student_id')
                ->orderByDesc('a')->pluck('a', 'student_id');
            $classSize = $classAvgs->count();
            $ids = $classAvgs->keys()->values();
            $pos = $ids->search((int) $studentId);
            $rank = $pos === false ? null : $pos + 1;
        }

        $badge = $this->badgeFor($overall, $rank, $classSize, collect($months)->last()['is_critical'] ?? false);

        return response()->json([
            'student_id' => (int) $studentId,
            'subjects' => $subjects,
            'months' => $months,
            'overall' => $overall,
            'stars' => $overall === null ? 0 : round(min(5, $overall / 20), 1),
            'rank' => $rank,
            'class_size' => $classSize,
            'badge' => $badge,
            'is_critical' => collect($months)->last()['is_critical'] ?? false,
        ]);
    }

    private function badgeFor(?float $avg, ?int $rank, ?int $size, bool $critical): array
    {
        if ($critical) {
            return ['key' => 'critical', 'label_en' => 'Needs care', 'label_fa' => 'نیازمند توجه', 'color' => '#dc2626'];
        }
        if ($rank === 1 && $size > 1) {
            return ['key' => 'topper', 'label_en' => 'Topper', 'label_fa' => 'ممتاز', 'color' => '#ca8a04'];
        }
        if ($avg === null) {
            return ['key' => 'none', 'label_en' => 'Not rated', 'label_fa' => 'بدون ارزیابی', 'color' => '#94a3b8'];
        }
        if ($avg >= 85) {
            return ['key' => 'excellent', 'label_en' => 'Excellent', 'label_fa' => 'عالی', 'color' => '#16a34a'];
        }
        if ($avg >= 70) {
            return ['key' => 'good', 'label_en' => 'Good', 'label_fa' => 'خوب', 'color' => '#22c55e'];
        }
        if ($avg >= 55) {
            return ['key' => 'average', 'label_en' => 'Average', 'label_fa' => 'متوسط', 'color' => '#f59e0b'];
        }
        return ['key' => 'weak', 'label_en' => 'Weak', 'label_fa' => 'ضعیف', 'color' => '#ef4444'];
    }

    /* ── Send this month's evaluation to parents via WhatsApp ─────── */
    public function sendWhatsApp(Request $request, Evaluation $evaluation)
    {
        $wa = app(\App\Services\WhatsAppService::class);
        $lang = \App\Models\CrmSetting::current()->default_language ?: 'fa';
        $monthName = $lang === 'en' ? ($this->monthsEn[$evaluation->month_shamsi] ?? '') : ($this->monthsFa[$evaluation->month_shamsi] ?? '');

        $subjects = Subject::orderBy('sort_order')->orderBy('id')->get()
            ->mapWithKeys(fn ($s) => [$s->id => $lang === 'en' ? ($s->name_en ?: $s->name) : ($s->name_fa ?: $s->name)]);
        $students = Student::with('schoolClass')->where('class_id', $evaluation->class_id)->where('status', 'active')->get();
        $notes = EvaluationStudentNote::where('evaluation_id', $evaluation->id)->get()->keyBy('student_id');

        $n = 0;
        foreach ($students as $student) {
            $res = EvaluationResult::where('evaluation_id', $evaluation->id)->where('student_id', $student->id)
                ->whereNotNull('marks')->get();
            if ($res->isEmpty()) {
                continue;
            }
            $avg = round($res->avg('marks'));
            $lines = $res->map(fn ($r) => '• '.($subjects[$r->subject_id] ?? '—').': '.round($r->marks).'%')->implode("\n");
            $note = $notes[$student->id]->note ?? '';

            $recipient = $wa->parentRecipient($student);
            $header = $lang === 'en'
                ? "{{school}}\nMonthly evaluation — {$monthName}\nStudent: {{student_name}} ({{class}})\nAverage: {$avg}%\n\n{$lines}"
                : "{{school}}\nارزیابی ماهوار — {$monthName}\nشاگرد: {{student_name}} (صنف {{class}})\nمیانگین: {$avg}٪\n\n{$lines}";
            if ($note) {
                $header .= ($lang === 'en' ? "\n\nNote: " : "\n\nیادداشت: ").$note;
            }
            $body = $wa->render($header, $recipient);
            $dedupe = "evaluation|{$evaluation->id}|{$student->id}";
            $n += $wa->queue($recipient, $body, null, 'evaluation_summary', $dedupe) ? 1 : 0;
        }
        ActivityLog::record('update', 'evaluation', "Sent evaluation #{$evaluation->id} to {$n} parents via WhatsApp", $evaluation);

        return response()->json(['queued' => $n]);
    }

    private function recomputeAvg(Evaluation $evaluation): void
    {
        $avg = EvaluationResult::where('evaluation_id', $evaluation->id)->whereNotNull('marks')->avg('marks');
        $evaluation->update(['class_avg' => $avg !== null ? round($avg, 2) : null]);
    }

    public function destroy(Evaluation $evaluation)
    {
        $evaluation->delete();
        ActivityLog::record('delete', 'evaluation', "Deleted evaluation #{$evaluation->id}", $evaluation);

        return response()->json(['success' => true]);
    }

    public function restore($id)
    {
        $evaluation = Evaluation::withTrashed()->findOrFail($id);
        $evaluation->restore();

        return response()->json(['data' => $evaluation]);
    }
}
