<?php

namespace Modules\Academic\Http\Controllers;

use App\Http\Controllers\Controller;
use Modules\Academic\Models\Subject;
use Modules\Academic\Models\Classroom;
use Modules\Academic\Http\Requests\StoreSubjectRequest;
use Modules\Academic\Http\Requests\UpdateSubjectRequest;
use Modules\Teachers\Models\Teacher;
use Illuminate\Http\Request;
use Inertia\Inertia;
use Inertia\Response;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\DB;

class SubjectController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth');
        $this->authorizeResource(Subject::class, 'subject');
    }

    /**
     * Display a listing of the resource.
     */
    public function index(Request $request): Response
    {
        $user = $request->user();
        $query = Subject::with(['classrooms.academicYear', 'teachers']);

        // Role-based filtering
        if ($user->role === 'teacher') {
            $query->whereHas('teachers', function ($q) use ($user) {
                $q->where('teacher_id', $user->id);
            });
        }

        // Apply filters
        if ($request->classroom_id) {
            $query->whereHas('classrooms', function ($q) use ($request) {
                $q->where('classroom_id', $request->classroom_id);
            });
        }

        if ($request->teacher_id) {
            $query->whereHas('teachers', function ($q) use ($request) {
                $q->where('teacher_id', $request->teacher_id);
            });
        }

        if ($request->search) {
            $search = $request->search;
            $query->where(function ($q) use ($search) {
                $q->where('name', 'like', "%{$search}%")
                  ->orWhere('code', 'like', "%{$search}%")
                  ->orWhere('description', 'like', "%{$search}%");
            });
        }

        if ($request->status !== null) {
            $query->where('is_active', $request->status === 'active');
        }

        $subjects = $query->withCount(['teachers', 'classrooms'])->orderBy('name')->paginate(20);

        // Get dropdown data
        $classrooms = Classroom::with('academicYear')->orderBy('name')->get();
        $teachers = Teacher::with('user')->get();

        // Get statistics
        $statistics = [
            'total' => Subject::count(),
            'active' => Subject::where('is_active', true)->count(),
            'assigned_teachers' => DB::table('teacher_subjects')
                ->distinct('teacher_id')
                ->count(),
            'classrooms' => DB::table('classroom_subjects')
                ->distinct('classroom_id')
                ->count(),
        ];

        return Inertia::render('Academic/Subjects/Index', [
            'subjects' => $subjects,
            'classrooms' => $classrooms,
            'teachers' => $teachers,
            'statistics' => $statistics,
            'filters' => [
                'classroom_id' => $request->classroom_id,
                'teacher_id' => $request->teacher_id,
                'search' => $request->search,
                'status' => $request->status,
            ],
        ]);
    }

    /**
     * Show the form for creating a new resource.
     */
    public function create(): Response
    {
        $classrooms = Classroom::with('academicYear')->orderBy('name')->get();
        $teachers = Teacher::with('user')->get();

        return Inertia::render('Academic/Subjects/Create', [
            'classrooms' => $classrooms,
            'teachers' => $teachers,
        ]);
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(StoreSubjectRequest $request): RedirectResponse
    {
        $validated = $request->validated();

        try {
            DB::beginTransaction();

            $subject = Subject::create($validated);

            DB::commit();

            return redirect()
                ->route('subjects.show', $subject)
                ->with('success', 'Subject created successfully.');

        } catch (\Exception $e) {
            DB::rollBack();

            return back()
                ->withInput()
                ->withErrors(['error' => 'Failed to create subject: ' . $e->getMessage()]);
        }
    }

    /**
     * Display the specified resource.
     */
    public function show(Subject $subject): Response
    {
        $subject->load([
            'classrooms.academicYear',
            'teachers.user',
            'results.student.user',
            'results.examType'
        ]);

        // Get subject statistics
        $statistics = [
            'total_results' => $subject->results()->count(),
            'students_with_results' => $subject->results()->distinct('student_id')->count(),
            'average_marks' => $subject->results()->avg('marks'),
            'highest_marks' => $subject->results()->max('marks'),
            'lowest_marks' => $subject->results()->min('marks'),
        ];

        // Get recent results
        $recentResults = $subject->results()
            ->with(['student.user', 'examType'])
            ->latest('entered_at')
            ->limit(10)
            ->get();

        // Get enrolled students from all classrooms that have this subject
        $enrolledStudents = collect();
        foreach ($subject->classrooms as $classroom) {
            $students = DB::table('enrollments')
                ->join('students', 'enrollments.student_id', '=', 'students.id')
                ->join('users', 'students.user_id', '=', 'users.id')
                ->where('enrollments.classroom_id', $classroom->id)
                ->where('enrollments.is_active', true)
                ->select('students.*', 'users.name', 'users.email')
                ->get();
            $enrolledStudents = $enrolledStudents->merge($students);
        }

        return Inertia::render('Academic/Subjects/Show', [
            'subject' => $subject,
            'statistics' => $statistics,
            'recentResults' => $recentResults,
            'enrolledStudents' => $enrolledStudents->unique('id'),
        ]);
    }

    /**
     * Show the form for editing the specified resource.
     */
    public function edit(Subject $subject): Response
    {
        $subject->load(['classrooms', 'teachers.user']);

        $classrooms = Classroom::with('academicYear')->orderBy('name')->get();
        $teachers = Teacher::with('user')->get();

        return Inertia::render('Academic/Subjects/Edit', [
            'subject' => $subject,
            'classrooms' => $classrooms,
            'teachers' => $teachers,
        ]);
    }

    /**
     * Update the specified resource in storage.
     */
    public function update(UpdateSubjectRequest $request, Subject $subject): RedirectResponse
    {
        $validated = $request->validated();

        try {
            DB::beginTransaction();

            $subject->update($validated);

            DB::commit();

            return redirect()
                ->route('subjects.show', $subject)
                ->with('success', 'Subject updated successfully.');

        } catch (\Exception $e) {
            DB::rollBack();

            return back()
                ->withInput()
                ->withErrors(['error' => 'Failed to update subject: ' . $e->getMessage()]);
        }
    }

    /**
     * Remove the specified resource from storage.
     */
    public function destroy(Subject $subject): RedirectResponse
    {
        try {
            DB::beginTransaction();

            // Check if subject has results
            if ($subject->results()->exists()) {
                throw \Illuminate\Validation\ValidationException::withMessages([
                    'subject' => 'Cannot delete subject with existing results.'
                ]);
            }

            // Check if subject is assigned to classrooms
            if ($subject->classrooms()->exists()) {
                throw \Illuminate\Validation\ValidationException::withMessages([
                    'subject' => 'Cannot delete subject that is assigned to classrooms.'
                ]);
            }

            // Check if subject is assigned to teachers
            if ($subject->teachers()->exists()) {
                throw \Illuminate\Validation\ValidationException::withMessages([
                    'subject' => 'Cannot delete subject that is assigned to teachers.'
                ]);
            }

            $subject->delete();

            DB::commit();

            return redirect()
                ->route('subjects.index')
                ->with('success', 'Subject deleted successfully.');

        } catch (\Exception $e) {
            DB::rollBack();

            return back()
                ->withErrors(['error' => 'Failed to delete subject: ' . $e->getMessage()]);
        }
    }

    /**
     * Toggle subject status
     */
    public function toggleStatus(Subject $subject): RedirectResponse
    {
        $this->authorize('update', $subject);

        try {
            DB::beginTransaction();

            $subject->update(['is_active' => !$subject->is_active]);

            $message = $subject->is_active ? 'Subject activated successfully.' : 'Subject deactivated successfully.';

            DB::commit();

            return back()->with('success', $message);

        } catch (\Exception $e) {
            DB::rollBack();

            return back()
                ->withErrors(['error' => 'Failed to update subject status: ' . $e->getMessage()]);
        }
    }

    /**
     * Get subjects for a classroom
     */
    public function getSubjectsForClassroom(Request $request): \Illuminate\Http\JsonResponse
    {
        $request->validate([
            'classroom_id' => 'required|exists:classrooms,id',
        ]);

        $subjects = Subject::whereHas('classrooms', function ($query) use ($request) {
                $query->where('classroom_id', $request->classroom_id);
            })
            ->where('is_active', true)
            ->with('teachers.user')
            ->orderBy('name')
            ->get();

        return response()->json($subjects);
    }

    /**
     * Assign teacher to subject
     */
    public function assignTeacher(Request $request, Subject $subject): RedirectResponse
    {
        $this->authorize('update', $subject);

        $validated = $request->validate([
            'teacher_id' => 'required|exists:users,id',
        ]);

        try {
            DB::beginTransaction();

            // Verify teacher exists
            $teacher = Teacher::where('user_id', $validated['teacher_id'])->first();
            if (!$teacher) {
                return back()
                    ->withErrors(['teacher_id' => 'Selected user is not a teacher.']);
            }

            // Assign teacher to subject using the many-to-many relationship
            $subject->teachers()->syncWithoutDetaching([$teacher->id]);

            DB::commit();

            return back()->with('success', 'Teacher assigned successfully.');

        } catch (\Exception $e) {
            DB::rollBack();

            return back()
                ->withErrors(['error' => 'Failed to assign teacher: ' . $e->getMessage()]);
        }
    }
}
