<?php

declare(strict_types=1);

namespace App\Http\Controllers\Api\Admin;

use App\Http\Controllers\Controller;
use App\Models\ExportJob;
use App\Models\Question;
use App\Models\QuizAttempt;
use App\Models\User;
use App\Models\WrongQuestion;
use App\Support\ApiResponse;
use hg\apidoc\annotation as Apidoc;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;

#[Apidoc\Group('后台')]
#[Apidoc\Title('统计报表')]
#[Apidoc\RouteMiddleware(['jwt.auth'])]
final class ReportController extends Controller
{
    #[Apidoc\Title('报表概览')]
    #[Apidoc\Url('/api/admin/reports/overview')]
    #[Apidoc\Method('GET')]
    #[Apidoc\RouteMiddleware(['permission:reports'])]
    public function overview(): JsonResponse
    {
        $attempts = QuizAttempt::query();
        $total = (clone $attempts)->count();
        $correct = (clone $attempts)->sum('correct_count');
        $questions = (clone $attempts)->sum('total_questions');

        return ApiResponse::success([
            'users' => User::query()->count(),
            'questions' => Question::query()->count(),
            'attempts' => $total,
            'wrong_questions' => WrongQuestion::query()->whereNull('mastered_at')->count(),
            'accuracy' => $questions > 0 ? round($correct / $questions * 100, 2) : 0,
        ]);
    }

    #[Apidoc\Title('练习趋势')]
    #[Apidoc\Url('/api/admin/reports/trends')]
    #[Apidoc\Method('GET')]
    #[Apidoc\RouteMiddleware(['permission:reports'])]
    public function trends(): JsonResponse
    {
        $rows = QuizAttempt::query()
            ->selectRaw('date(started_at) as day, count(*) as attempts, sum(correct_count) as correct_count, sum(total_questions) as total_questions')
            ->where('started_at', '>=', now()->subDays(14))
            ->groupBy('day')
            ->orderBy('day')
            ->get();

        return ApiResponse::success($rows);
    }

    #[Apidoc\Title('题目错误率')]
    #[Apidoc\Url('/api/admin/reports/question-errors')]
    #[Apidoc\Method('GET')]
    #[Apidoc\RouteMiddleware(['permission:reports'])]
    public function questionErrors(Request $request): JsonResponse
    {
        $rows = DB::table('quiz_attempt_questions')
            ->join('questions', 'questions.id', '=', 'quiz_attempt_questions.question_id')
            ->selectRaw('questions.id, questions.content, count(*) as attempts, sum(case when is_correct = 0 then 1 else 0 end) as wrong_count')
            ->groupBy('questions.id', 'questions.content')
            ->orderByDesc('wrong_count')
            ->paginate((int) $request->query('per_page', 20));

        return ApiResponse::page($rows);
    }

    #[Apidoc\Title('班级排行')]
    #[Apidoc\Url('/api/admin/reports/class-ranking')]
    #[Apidoc\Method('GET')]
    #[Apidoc\RouteMiddleware(['permission:reports'])]
    public function classRanking(Request $request): JsonResponse
    {
        $rows = DB::table('classes')
            ->leftJoin('class_members', 'class_members.class_id', '=', 'classes.id')
            ->leftJoin('quiz_attempts', 'quiz_attempts.user_id', '=', 'class_members.user_id')
            ->when($request->user()->role !== 'admin', fn ($query) => $query->where('classes.owner_id', $request->user()->id))
            ->selectRaw('classes.id, classes.name, count(distinct class_members.user_id) as members_count, count(distinct quiz_attempts.id) as attempts, coalesce(sum(quiz_attempts.correct_count), 0) as correct_count, coalesce(sum(quiz_attempts.total_questions), 0) as total_questions')
            ->groupBy('classes.id', 'classes.name')
            ->orderByDesc('attempts')
            ->limit(20)
            ->get()
            ->map(function (object $row): array {
                $totalQuestions = (int) $row->total_questions;

                return [
                    'id' => (int) $row->id,
                    'name' => $row->name,
                    'members_count' => (int) $row->members_count,
                    'attempts' => (int) $row->attempts,
                    'correct_count' => (int) $row->correct_count,
                    'total_questions' => $totalQuestions,
                    'accuracy' => $totalQuestions > 0 ? round((int) $row->correct_count / $totalQuestions * 100, 2) : 0,
                ];
            });

        return ApiResponse::success($rows);
    }

    #[Apidoc\Title('题库和分类掌握度')]
    #[Apidoc\Url('/api/admin/reports/mastery')]
    #[Apidoc\Method('GET')]
    #[Apidoc\RouteMiddleware(['permission:reports'])]
    public function mastery(Request $request): JsonResponse
    {
        $query = DB::table('quiz_attempt_questions')
            ->join('quiz_attempts', 'quiz_attempts.id', '=', 'quiz_attempt_questions.quiz_attempt_id')
            ->join('questions', 'questions.id', '=', 'quiz_attempt_questions.question_id')
            ->join('question_banks', 'question_banks.id', '=', 'questions.question_bank_id')
            ->leftJoin('question_categories', 'question_categories.id', '=', 'questions.category_id')
            ->whereNotNull('quiz_attempt_questions.is_correct')
            ->when($request->user()->role !== 'admin', fn ($builder) => $builder->where('question_banks.owner_id', $request->user()->id));

        $banks = (clone $query)
            ->selectRaw('question_banks.id, question_banks.name, count(*) as attempts, sum(case when quiz_attempt_questions.is_correct = 1 then 1 else 0 end) as correct_count')
            ->groupBy('question_banks.id', 'question_banks.name')
            ->orderByDesc('attempts')
            ->limit(20)
            ->get()
            ->map(fn (object $row): array => $this->masteryRow($row));

        $categories = (clone $query)
            ->selectRaw('question_banks.name as bank_name, question_categories.id, coalesce(question_categories.name, "未分类") as name, count(*) as attempts, sum(case when quiz_attempt_questions.is_correct = 1 then 1 else 0 end) as correct_count')
            ->groupBy('question_banks.name', 'question_categories.id', 'question_categories.name')
            ->orderByDesc('attempts')
            ->limit(30)
            ->get()
            ->map(fn (object $row): array => $this->masteryRow($row) + ['bank_name' => $row->bank_name]);

        return ApiResponse::success([
            'banks' => $banks,
            'categories' => $categories,
        ]);
    }

    #[Apidoc\Title('报表导出')]
    #[Apidoc\Url('/api/admin/reports/export')]
    #[Apidoc\Method('POST')]
    #[Apidoc\RouteMiddleware(['permission:reports'])]
    public function export(Request $request): JsonResponse
    {
        $payload = [
            'overview' => $this->overview()->getData(true)['data'],
            'trends' => $this->trends()->getData(true)['data'],
            'class_ranking' => $this->classRanking($request)->getData(true)['data'],
            'mastery' => $this->mastery($request)->getData(true)['data'],
        ];
        $path = 'exports/report-'.now()->format('YmdHis').'.json';
        Storage::put($path, json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));

        $job = ExportJob::create([
            'user_id' => $request->user()->id,
            'type' => 'report',
            'file_path' => $path,
            'payload' => $payload,
        ]);

        return ApiResponse::success($job, '报表已导出');
    }

    private function masteryRow(object $row): array
    {
        $attempts = (int) $row->attempts;
        $correct = (int) $row->correct_count;

        return [
            'id' => $row->id === null ? null : (int) $row->id,
            'name' => $row->name,
            'attempts' => $attempts,
            'correct_count' => $correct,
            'accuracy' => $attempts > 0 ? round($correct / $attempts * 100, 2) : 0,
        ];
    }
}
