<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Models\Branch;
use App\Models\Evaluation;
use App\Models\EvaluationResult;
use App\Models\SchoolClass;
use App\Models\Student;
use App\Support\SystemConfig;
use Illuminate\Support\Facades\DB;

/**
 * Public "Talents" board — the school's best students, per branch and per shift
 * (morning & afternoon only). No authentication: the link is meant to be shared
 * to family groups and social media. Monthly toppers plus a "student of the
 * week" for each week (rank 1 → week 1, rank 2 → week 2, …).
 */
class TalentsController extends Controller
{
    public function index()
    {
        $cfg = SystemConfig::all();
        if (! ($cfg['talents_public'] ?? true)) {
            return response()->json(['message' => 'The talents board is disabled.'], 404);
        }
        $topN = (int) ($cfg['top_students_count'] ?? 4);
        $weeks = (int) ($cfg['weeks_per_month'] ?? 4);
        $shifts = ['morning', 'afternoon', 'evening'];

        $branches = Branch::where('is_active', true)->orderBy('name')->get()->map(function ($br) use ($shifts, $topN, $weeks) {
            $shiftData = [];
            foreach ($shifts as $shift) {
                $classIds = SchoolClass::where('branch_id', $br->id)->where('shift', $shift)->pluck('id');
                $ranked = $this->rankStudents($classIds);

                $monthly = $ranked->take($topN)->values()->map(fn ($r, $i) => $r + ['rank' => $i + 1]);
                $weekly = [];
                for ($w = 0; $w < $weeks; $w++) {
                    $weekly[] = ['week' => $w + 1, 'student' => $ranked[$w] ?? null];
                }
                $shiftData[$shift] = ['weekly' => $weekly, 'monthly' => $monthly->values()];
            }

            return ['id' => $br->id, 'name' => $br->name, 'code' => $br->code, 'shifts' => $shiftData];
        })->filter(fn ($b) => collect($b['shifts'])->contains(fn ($s) => count($s['monthly']) > 0))->values();

        return response()->json([
            'school_name' => $cfg['school_name'] ?? 'School',
            'top_count' => $topN,
            'weeks' => $weeks,
            'generated_at' => now()->toDateTimeString(),
            'branches' => $branches,
        ]);
    }

    /**
     * Rank a set of classes' students by a blend of completed-evaluation
     * academic average (85%) and discipline (15%). Students flagged critical in
     * any evaluation are excluded — they can't be public toppers.
     */
    private function rankStudents($classIds)
    {
        if ($classIds->isEmpty()) {
            return collect();
        }
        $evalIds = Evaluation::whereIn('class_id', $classIds)->where('status', 'completed')->pluck('id');
        if ($evalIds->isEmpty()) {
            return collect();
        }
        $avgs = EvaluationResult::whereIn('evaluation_id', $evalIds)->whereNotNull('marks')
            ->select('student_id', DB::raw('AVG(marks) as a'))
            ->groupBy('student_id')->pluck('a', 'student_id');

        // Discipline score + critical flags from the same evaluations' notes.
        $disc = [];       // student_id => [sum%, count]
        $critical = [];   // student_id => true
        $keys = ['book', 'uniform', 'clean', 'behaved'];
        foreach (\App\Models\EvaluationStudentNote::whereIn('evaluation_id', $evalIds)->get() as $n) {
            if ($n->is_critical) {
                $critical[$n->student_id] = true;
            }
            $d = is_array($n->discipline) ? $n->discipline : (json_decode((string) $n->discipline, true) ?: []);
            if ($d) {
                $on = collect($keys)->filter(fn ($k) => ! empty($d[$k]))->count();
                $disc[$n->student_id][0] = ($disc[$n->student_id][0] ?? 0) + ($on / count($keys) * 100);
                $disc[$n->student_id][1] = ($disc[$n->student_id][1] ?? 0) + 1;
            }
        }

        $students = Student::whereIn('id', $avgs->keys())->where('status', 'active')
            ->with('schoolClass:id,name,name_fa')->get()->keyBy('id');

        $dw = 0.15; // discipline weight

        return $avgs->map(function ($avg, $sid) use ($students, $disc, $critical, $dw) {
            $s = $students[$sid] ?? null;
            if (! $s || isset($critical[$sid])) {
                return null;
            }
            $discScore = (isset($disc[$sid]) && $disc[$sid][1] > 0) ? $disc[$sid][0] / $disc[$sid][1] : $avg;
            $combined = $avg * (1 - $dw) + $discScore * $dw;

            return [
                'id' => $s->id,
                'name' => $s->full_name,
                'gender' => $s->gender,
                'photo' => $s->photo,
                'class_name' => $s->schoolClass?->name,
                'class_name_fa' => $s->schoolClass?->name_fa,
                'avg' => round($combined, 1),
                'academic' => round($avg, 1),
                'discipline' => round($discScore),
                'stars' => round(min(5, $combined / 20), 1),
            ];
        })->filter()->sortByDesc('avg')->values();
    }
}
