<?php

namespace Modules\Results\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Inertia\Inertia;
use Inertia\Response;
use Illuminate\Http\RedirectResponse;
use Modules\Results\Models\Result;
use Modules\Results\Models\StudentResultSummary;
use Modules\Results\Http\Requests\StoreResultRequest;
use Modules\Results\Http\Requests\ImportResultsRequest;
use Modules\Results\Services\ResultCalculationService;
use Modules\Results\Services\ResultCsvService;
use Modules\Academic\Models\AcademicYear;
use Modules\Academic\Models\ExamType;
use Modules\Academic\Models\Classroom;
use Modules\Academic\Models\Subject;
use Modules\Students\Models\Student;

class ResultsController extends Controller
{
    private ResultCalculationService $calculationService;
    private ResultCsvService $csvService;

    public function __construct(
        ResultCalculationService $calculationService,
        ResultCsvService $csvService
    ) {
        $this->calculationService = $calculationService;
        $this->csvService = $csvService;

        $this->authorizeResource(Result::class, 'result');
    }

    /**
     * Display a listing of the resource.
     */
    public function index(Request $request): Response
    {
        $user = $request->user();

        // Get filter parameters
        $academicYearId = $request->get('academic_year_id');
        $examTypeId = $request->get('exam_type_id');
        $classroomId = $request->get('classroom_id');
        $subjectId = $request->get('subject_id');

        // If no academic year specified, use current academic year
        if (!$academicYearId) {
            $currentAcademicYear = AcademicYear::where('is_current', true)->first();
            if ($currentAcademicYear) {
                $academicYearId = $currentAcademicYear->id;
            }
        }

        // If no exam type specified, use most recent exam type for the academic year
        if (!$examTypeId && $academicYearId) {
            $mostRecentExamType = ExamType::where('academic_year_id', $academicYearId)
                ->where('is_active', true)
                ->orderBy('created_at', 'desc')
                ->first();
            if ($mostRecentExamType) {
                $examTypeId = $mostRecentExamType->id;
            }
        }

        // Prepare filters for the calculation service
        $filters = array_filter([
            'academic_year_id' => $academicYearId,
            'exam_type_id' => $examTypeId,
            'classroom_id' => $classroomId,
            'subject_id' => $subjectId,
        ]);

        // Get consolidated results
        $consolidatedResults = $this->calculationService->getConsolidatedResults($filters);

        // Apply role-based access control
        switch ($user->role) {
            case 'admin':
                // Admin can see all results
                break;

            case 'teacher':
                // Teachers can only see results for subjects they teach
                $teacherSubjects = collect();
                // Get subjects this teacher teaches
                $classroomSubjects = \Modules\Academic\Models\ClassroomSubject::where('teacher_id', $user->id)->get();
                $teacherSubjects = $classroomSubjects->pluck('subject_id')->toArray();

                $consolidatedResults = array_filter($consolidatedResults, function ($result) use ($teacherSubjects) {
                    return !empty(array_intersect(array_keys($result['subjects_data']), $teacherSubjects));
                });
                break;

            case 'student':
                // Students can only see their own results
                $student = \Modules\Students\Models\Student::where('user_id', $user->id)->first();
                if ($student) {
                    $consolidatedResults = array_filter($consolidatedResults, function ($result) use ($student) {
                        return $result['student']->id === $student->id;
                    });
                } else {
                    $consolidatedResults = [];
                }
                break;

            case 'guardian':
                // Guardians can see results of their students
                $guardian = \Modules\Guardians\Models\Guardian::where('user_id', $user->id)->first();
                if ($guardian) {
                    $childrenIds = $guardian->students()->pluck('students.id')->toArray();
                    $consolidatedResults = array_filter($consolidatedResults, function ($result) use ($childrenIds) {
                        return in_array($result['student']->id, $childrenIds);
                    });
                } else {
                    $consolidatedResults = [];
                }
                break;
        }

        // Convert to collection
        $consolidatedResults = collect($consolidatedResults);

        // Get all subjects that appear in the results for table columns (BEFORE pagination)
        $allSubjects = collect();
        foreach ($consolidatedResults as $result) {
            foreach ($result['subjects_data'] as $subjectData) {
                $subject = $subjectData['subject'];
                if (!$allSubjects->contains('id', $subject->id)) {
                    $allSubjects->push($subject);
                }
            }
        }
        $allSubjects = $allSubjects->sortBy('name')->values();

        // Paginate manually AFTER building allSubjects
        $perPage = 20;
        $currentPage = $request->get('page', 1);
        $total = $consolidatedResults->count();
        $results = $consolidatedResults->forPage($currentPage, $perPage)->values();

        // Create pagination data
        $paginationData = [
            'data' => $results,
            'current_page' => $currentPage,
            'per_page' => $perPage,
            'total' => $total,
            'last_page' => ceil($total / $perPage),
            'from' => ($currentPage - 1) * $perPage + 1,
            'to' => min($currentPage * $perPage, $total),
        ];

        // Get filter options
        $academicYears = AcademicYear::orderBy('start_date', 'desc')->get();
        $examTypes = ExamType::with('academicYear')->where('is_active', true)->get();
        $classrooms = $this->getAccessibleClassrooms($user);
        $subjects = Subject::where('is_active', true)->get();

        // Get current academic year and exam type info
        $currentAcademicYear = null;
        $currentExamType = null;

        if ($academicYearId) {
            $currentAcademicYear = AcademicYear::find($academicYearId);
        }

        if ($examTypeId) {
            $currentExamType = ExamType::find($examTypeId);
        }

        return Inertia::render('Results/Index', [
            'results' => $paginationData,
            'allSubjects' => $allSubjects,
            'filters' => [
                'academic_year_id' => $academicYearId,
                'exam_type_id' => $examTypeId,
                'classroom_id' => $classroomId,
                'subject_id' => $subjectId,
            ],
            'academicYears' => $academicYears,
            'examTypes' => $examTypes,
            'classrooms' => $classrooms,
            'subjects' => $subjects,
            'currentAcademicYear' => $currentAcademicYear,
            'currentExamType' => $currentExamType,
        ]);
    }

    /**
     * Show the form for creating a new resource.
     */
    public function create(Request $request): Response
    {
        $user = $request->user();

        // Get form data
        $academicYears = AcademicYear::where('is_active', true)->get();
        $examTypes = ExamType::where('is_active', true)->with('academicYear')->get();
        $classrooms = $this->getAccessibleClassrooms($user);
        $subjects = Subject::where('is_active', true)->get();
        $students = $this->getAccessibleStudents($user);

        return Inertia::render('Results/Create', [
            'academicYears' => $academicYears,
            'examTypes' => $examTypes,
            'classrooms' => $classrooms,
            'subjects' => $subjects,
            'students' => $students,
        ]);
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(StoreResultRequest $request): RedirectResponse
    {
        $validated = $request->validated();
        $validated['teacher_id'] = $request->user()->id;
        $validated['entered_at'] = now();

        $result = Result::create($validated);

        // Recalculate student summary
        try {
            $this->calculationService->calculateStudentSummary(
                $validated['student_id'],
                $validated['academic_year_id'],
                $validated['exam_type_id']
            );
        } catch (\Exception $e) {
            \Log::warning("Failed to calculate student summary: " . $e->getMessage());
        }

        return redirect()->route('results.index')
            ->with('success', 'Result created successfully.');
    }

    /**
     * Show the specified resource.
     */
    public function show(Result $result): Response
    {
        $this->authorize('view', $result);

        $result->load([
            'student.user',
            'subject',
            'classroom',
            'examType',
            'academicYear',
            'teacher'
        ]);

        // Get student's complete result data
        $resultData = $this->calculationService->getStudentResultData(
            $result->student_id,
            $result->academic_year_id,
            $result->exam_type_id
        );

        return Inertia::render('Results/Show', [
            'result' => $result,
            'studentData' => $resultData,
        ]);
    }

    /**
     * Show the form for editing the specified resource.
     */
    public function edit(Result $result): Response
    {
        $this->authorize('update', $result);

        $result->load(['student.user', 'subject', 'classroom', 'examType', 'academicYear']);

        // Get all necessary data for dropdowns
        $user = auth()->user();
        $academicYears = AcademicYear::orderBy('start_date', 'desc')->get();
        $examTypes = ExamType::with('academicYear')->where('is_active', true)->get();
        $classrooms = $this->getAccessibleClassrooms($user);
        $subjects = Subject::where('is_active', true)->get();
        $students = $this->getAccessibleStudents($user);

        return Inertia::render('Results/Edit', [
            'result' => $result,
            'academicYears' => $academicYears,
            'examTypes' => $examTypes,
            'classrooms' => $classrooms,
            'subjects' => $subjects,
            'students' => $students,
        ]);
    }

    /**
     * Update the specified resource in storage.
     */
    public function update(StoreResultRequest $request, Result $result): RedirectResponse
    {
        $this->authorize('update', $result);

        $validated = $request->validated();
        $result->update($validated);

        // Recalculate student summary
        try {
            $this->calculationService->calculateStudentSummary(
                $result->student_id,
                $result->academic_year_id,
                $result->exam_type_id
            );
        } catch (\Exception $e) {
            \Log::warning("Failed to recalculate student summary: " . $e->getMessage());
        }

        return redirect()->route('results.index')
            ->with('success', 'Result updated successfully.');
    }

    /**
     * Remove the specified resource from storage.
     */
    public function destroy(Result $result): RedirectResponse
    {
        $this->authorize('delete', $result);

        $studentId = $result->student_id;
        $academicYearId = $result->academic_year_id;
        $examTypeId = $result->exam_type_id;
        $classroomId = $result->classroom_id;

        $result->delete();

        // Check if this was the last result for this student-exam combination
        $remainingResults = Result::where('student_id', $studentId)
            ->where('academic_year_id', $academicYearId)
            ->where('exam_type_id', $examTypeId)
            ->count();

        if ($remainingResults === 0) {
            // Delete the student summary if no results remain
            try {
                \Modules\Results\Models\StudentResultSummary::where('student_id', $studentId)
                    ->where('exam_type_id', $examTypeId)
                    ->where('academic_year_id', $academicYearId)
                    ->delete();
            } catch (\Exception $e) {
                \Log::warning("Failed to delete student summary: " . $e->getMessage());
            }
        } else {
            // Recalculate student summary with remaining results
            try {
                $this->calculationService->calculateStudentSummary($studentId, $academicYearId, $examTypeId);
            } catch (\Exception $e) {
                \Log::warning("Failed to recalculate student summary after deletion: " . $e->getMessage());
            }
        }

        // Always recalculate classroom ranks after any deletion
        try {
            $this->calculationService->recalculateClassroomRanks($classroomId, $academicYearId, $examTypeId);
        } catch (\Exception $e) {
            \Log::warning("Failed to recalculate classroom ranks after deletion: " . $e->getMessage());
        }

        return redirect()->route('results.index')
            ->with('success', 'Result deleted successfully.');
    }

    /**
     * Show the form for creating multiple results for a student
     */
    public function createMultiple(Request $request): Response
    {
        $user = auth()->user();

        // Get all necessary data for dropdowns
        $academicYears = AcademicYear::orderBy('start_date', 'desc')->get();
        $examTypes = ExamType::with('academicYear')->where('is_active', true)->get();
        $classrooms = $this->getAccessibleClassrooms($user);
        $subjects = Subject::where('is_active', true)->get();
        $students = $this->getAccessibleStudents($user);

        return Inertia::render('Results/CreateMultiple', [
            'academicYears' => $academicYears,
            'examTypes' => $examTypes,
            'classrooms' => $classrooms,
            'subjects' => $subjects,
            'students' => $students,
            'prefilledData' => $request->only(['student_id', 'academic_year_id', 'exam_type_id', 'classroom_id', 'edit_mode']),
        ]);
    }

    /**
     * Store multiple results for a student
     */
    public function storeMultiple(Request $request): RedirectResponse
    {
        $request->validate([
            'results' => 'required|array|min:1',
            'results.*.student_id' => 'required|exists:students,id',
            'results.*.subject_id' => 'required|exists:subjects,id',
            'results.*.academic_year_id' => 'required|exists:academic_years,id',
            'results.*.exam_type_id' => 'required|exists:exam_types,id',
            'results.*.classroom_id' => 'required|exists:classrooms,id',
            'results.*.marks' => 'required|numeric|min:0|max:100',
            'results.*.grade' => 'required|string|max:5',
            'results.*.points' => 'required|integer|min:0|max:12',
        ]);

        $user = auth()->user();
        $results = $request->input('results');
        $studentId = $results[0]['student_id'];
        $academicYearId = $results[0]['academic_year_id'];
        $examTypeId = $results[0]['exam_type_id'];
        $classroomId = $results[0]['classroom_id'];

        foreach ($results as $resultData) {
            $resultData['teacher_id'] = $user->id;
            $resultData['entered_at'] = now();

            // Check if result already exists for this combination
            $existingResult = Result::where([
                'student_id' => $resultData['student_id'],
                'subject_id' => $resultData['subject_id'],
                'classroom_id' => $resultData['classroom_id'],
                'academic_year_id' => $resultData['academic_year_id'],
                'exam_type_id' => $resultData['exam_type_id'],
            ])->first();

            if ($existingResult) {
                // Update existing result
                $existingResult->update([
                    'marks' => $resultData['marks'],
                    'grade' => $resultData['grade'],
                    'points' => $resultData['points'],
                    'teacher_id' => $resultData['teacher_id'],
                    'entered_at' => $resultData['entered_at'],
                ]);
            } else {
                // Create new result
                Result::create($resultData);
            }
        }

        // Recalculate student summary
        try {
            $this->calculationService->calculateStudentSummary($studentId, $academicYearId, $examTypeId);

            // Recalculate classroom ranks after creating new results
            $this->calculationService->recalculateClassroomRanks($classroomId, $academicYearId, $examTypeId);
        } catch (\Exception $e) {
            \Log::warning("Failed to calculate student summary: " . $e->getMessage());
        }

        return redirect()->route('results.index')
            ->with('success', 'Results saved successfully.');
    }

    /**
     * Show the form for editing multiple results for a student
     */
    public function editMultiple(Student $student, ExamType $examType, AcademicYear $academicYear): Response
    {
        $user = auth()->user();

        // Get existing results for this student, exam type, and academic year
        $existingResults = Result::where('student_id', $student->id)
            ->where('exam_type_id', $examType->id)
            ->where('academic_year_id', $academicYear->id)
            ->with(['subject'])
            ->get();

        // Get all necessary data for dropdowns
        $academicYears = AcademicYear::orderBy('start_date', 'desc')->get();
        $examTypes = ExamType::with('academicYear')->where('is_active', true)->get();
        $classrooms = $this->getAccessibleClassrooms($user);
        $subjects = Subject::where('is_active', true)->get();
        $students = $this->getAccessibleStudents($user);

        return Inertia::render('Results/EditMultiple', [
            'student' => $student->load(['user', 'enrollments.classroom']),
            'examType' => $examType,
            'academicYear' => $academicYear,
            'existingResults' => $existingResults,
            'academicYears' => $academicYears,
            'examTypes' => $examTypes,
            'classrooms' => $classrooms,
            'subjects' => $subjects,
            'students' => $students,
        ]);
    }

    /**
     * Update multiple results for a student
     */
    public function updateMultiple(Request $request): RedirectResponse
    {
        \Log::info('UpdateMultiple called with data:', $request->all());

        $request->validate([
            'student_id' => 'required|exists:students,id',
            'academic_year_id' => 'required|exists:academic_years,id',
            'exam_type_id' => 'required|exists:exam_types,id',
            'classroom_id' => 'required|exists:classrooms,id',
            'results' => 'required|array|min:1',
            'results.*.id' => 'nullable|exists:results,id',
            'results.*.subject_id' => 'required|exists:subjects,id',
            'results.*.marks' => 'required|numeric|min:0|max:100',
            'results.*.grade' => 'required|string|max:5',
            'results.*.points' => 'required|integer|min:0|max:12',
        ]);

        $user = auth()->user();
        $studentId = $request->input('student_id');
        $academicYearId = $request->input('academic_year_id');
        $examTypeId = $request->input('exam_type_id');
        $classroomId = $request->input('classroom_id');
        $results = $request->input('results');

        foreach ($results as $resultData) {
            if (isset($resultData['id']) && $resultData['id']) {
                // Update existing result
                $result = Result::findOrFail($resultData['id']);
                $result->update([
                    'marks' => $resultData['marks'],
                    'grade' => $resultData['grade'],
                    'points' => $resultData['points'],
                ]);
            } else {
                // Create new result
                Result::create([
                    'student_id' => $studentId,
                    'subject_id' => $resultData['subject_id'],
                    'academic_year_id' => $academicYearId,
                    'exam_type_id' => $examTypeId,
                    'classroom_id' => $classroomId,
                    'marks' => $resultData['marks'],
                    'grade' => $resultData['grade'],
                    'points' => $resultData['points'],
                    'teacher_id' => $user->id,
                    'entered_at' => now(),
                ]);
            }
        }

        // Recalculate student summary
        try {
            $this->calculationService->calculateStudentSummary($studentId, $academicYearId, $examTypeId);

            // Recalculate classroom ranks after update
            $this->calculationService->recalculateClassroomRanks($classroomId, $academicYearId, $examTypeId);
        } catch (\Exception $e) {
            \Log::warning("Failed to recalculate student summary: " . $e->getMessage());
        }

        return redirect()->route('results.index')
            ->with('success', 'Results updated successfully.');
    }

    /**
     * Delete multiple results for a student
     */
    public function deleteMultiple(Request $request): RedirectResponse
    {
        $request->validate([
            'student_id' => 'required|exists:students,id',
            'academic_year_id' => 'required|exists:academic_years,id',
            'exam_type_id' => 'required|exists:exam_types,id',
        ]);

        $studentId = $request->input('student_id');
        $academicYearId = $request->input('academic_year_id');
        $examTypeId = $request->input('exam_type_id');

        // Find all results for this student, exam type, and academic year
        $results = Result::where('student_id', $studentId)
            ->where('exam_type_id', $examTypeId)
            ->where('academic_year_id', $academicYearId)
            ->get();

        if ($results->isEmpty()) {
            return redirect()->route('results.index')
                ->with('error', 'No results found to delete.');
        }

        // Check authorization for each result
        foreach ($results as $result) {
            $this->authorize('delete', $result);
        }

        // Delete all results
        $deletedCount = $results->count();
        foreach ($results as $result) {
            $result->delete();
        }

        // Get classroom ID before deleting summary for rank recalculation
        $classroomId = null;
        $summary = \Modules\Results\Models\StudentResultSummary::where('student_id', $studentId)
            ->where('exam_type_id', $examTypeId)
            ->where('academic_year_id', $academicYearId)
            ->first();

        if ($summary) {
            $classroomId = $summary->classroom_id;
        }

        // Delete the student summary for this exam type
        try {
            \Modules\Results\Models\StudentResultSummary::where('student_id', $studentId)
                ->where('exam_type_id', $examTypeId)
                ->where('academic_year_id', $academicYearId)
                ->delete();
        } catch (\Exception $e) {
            \Log::warning("Failed to delete student summary: " . $e->getMessage());
        }

        // Recalculate ranks for the classroom after deletion
        if ($classroomId) {
            try {
                $this->calculationService->recalculateClassroomRanks($classroomId, $academicYearId, $examTypeId);
            } catch (\Exception $e) {
                \Log::warning("Failed to recalculate ranks after deletion: " . $e->getMessage());
            }
        }

        return redirect()->route('results.index')
            ->with('success', "Successfully deleted {$deletedCount} result(s).");
    }

    /**
     * Show import form
     */
    public function importForm(Request $request): Response
    {
        $this->authorize('import', Result::class);

        $user = $request->user();
        $academicYears = AcademicYear::where('is_active', true)->get();
        $examTypes = ExamType::where('is_active', true)->with('academicYear')->get();
        $classrooms = $this->getAccessibleClassrooms($user);

        return Inertia::render('Results/Import', [
            'academicYears' => $academicYears,
            'examTypes' => $examTypes,
            'classrooms' => $classrooms,
        ]);
    }

    /**
     * Import results from CSV
     */
    public function import(ImportResultsRequest $request): RedirectResponse
    {
        $this->authorize('import', Result::class);

        $validated = $request->validated();

        try {
            $importResult = $this->csvService->importResults(
                $request->file('csv_file'),
                $validated['academic_year_id'],
                $validated['exam_type_id'],
                $validated['classroom_id'],
                $request->user()->id
            );

            $message = "Import completed. {$importResult['success_count']} records imported successfully.";
            if ($importResult['error_count'] > 0) {
                $message .= " {$importResult['error_count']} records failed.";
            }

            return redirect()->route('results.index')
                ->with('success', $message)
                ->with('import_details', $importResult);

        } catch (\Exception $e) {
            return redirect()->back()
                ->with('error', 'Import failed: ' . $e->getMessage());
        }
    }

    /**
     * Export results to CSV
     */
    public function export(Request $request)
    {
        $this->authorize('export', Result::class);

        $request->validate([
            'classroom_id' => 'required|integer|exists:classrooms,id',
            'academic_year_id' => 'required|integer|exists:academic_years,id',
            'exam_type_id' => 'required|integer|exists:exam_types,id',
        ]);

        try {
            $csvContent = $this->csvService->exportResults(
                $request->classroom_id,
                $request->academic_year_id,
                $request->exam_type_id
            );

            $classroom = Classroom::findOrFail($request->classroom_id);
            $examType = ExamType::findOrFail($request->exam_type_id);
            $filename = "results_{$classroom->name}_{$examType->name}_" . date('Y-m-d') . ".csv";

            return response($csvContent)
                ->header('Content-Type', 'text/csv')
                ->header('Content-Disposition', "attachment; filename=\"{$filename}\"");

        } catch (\Exception $e) {
            return redirect()->back()
                ->with('error', 'Export failed: ' . $e->getMessage());
        }
    }

    /**
     * Download import template
     */
    public function downloadTemplate(Request $request)
    {
        $this->authorize('import', Result::class);

        $request->validate([
            'classroom_id' => 'required|integer|exists:classrooms,id',
            'academic_year_id' => 'required|integer|exists:academic_years,id',
        ]);

        try {
            $csvContent = $this->csvService->generateImportTemplate(
                $request->classroom_id,
                $request->academic_year_id
            );

            $classroom = Classroom::findOrFail($request->classroom_id);
            $filename = "import_template_{$classroom->name}_" . date('Y-m-d') . ".csv";

            return response($csvContent)
                ->header('Content-Type', 'text/csv')
                ->header('Content-Disposition', "attachment; filename=\"{$filename}\"");

        } catch (\Exception $e) {
            return redirect()->back()
                ->with('error', 'Template generation failed: ' . $e->getMessage());
        }
    }

    /**
     * Get classrooms accessible to the user
     */
    private function getAccessibleClassrooms($user)
    {
        switch ($user->role) {
            case 'admin':
                return Classroom::with('academicYear')->get();

            case 'teacher':
                return Classroom::whereHas('subjects', function ($query) use ($user) {
                    $query->where('teacher_id', $user->id);
                })->with('academicYear')->get();

            case 'student':
                return $user->student ?
                    Classroom::whereHas('enrollments', function ($query) use ($user) {
                        $query->where('student_id', $user->student->id)
                              ->where('is_active', true);
                    })->with('academicYear')->get() : collect();

            case 'guardian':
                return $user->guardian ?
                    Classroom::whereHas('enrollments.student.guardians', function ($query) use ($user) {
                        $query->where('guardian_id', $user->guardian->id);
                    })->with('academicYear')->get() : collect();

            default:
                return collect();
        }
    }

    /**
     * Get students accessible to the user
     */
    private function getAccessibleStudents($user)
    {
        switch ($user->role) {
            case 'admin':
                return Student::with(['user', 'enrollments.classroom'])->get();

            case 'teacher':
                return Student::whereHas('enrollments.classroom.subjects', function ($query) use ($user) {
                    $query->where('teacher_id', $user->id);
                })->with(['user', 'enrollments.classroom'])->get();

            case 'student':
                return $user->student ? collect([$user->student->load(['user', 'enrollments.classroom'])]) : collect();

            case 'guardian':
                return $user->guardian ?
                    $user->guardian->students()->with(['user', 'enrollments.classroom'])->get() : collect();

            default:
                return collect();
        }
    }
}
