<?php

namespace Modules\Enrollment\Services;

use Modules\Enrollment\Models\Enrollment;
use Modules\Students\Models\Student;
use Modules\Academic\Models\Classroom;
use Modules\Academic\Models\AcademicYear;
use Illuminate\Support\Facades\DB;
use Illuminate\Pagination\LengthAwarePaginator;
use Carbon\Carbon;

class EnrollmentService
{
    /**
     * Get enrollments with filters and pagination
     */
    public function getEnrollments(array $filters = []): LengthAwarePaginator
    {
        $query = Enrollment::with(['student.user', 'classroom', 'academicYear']);

        // Apply filters
        if (!empty($filters['academic_year_id'])) {
            $query->where('academic_year_id', $filters['academic_year_id']);
        }

        if (!empty($filters['classroom_id'])) {
            $query->where('classroom_id', $filters['classroom_id']);
        }

        if (!empty($filters['status'])) {
            $query->where('is_active', $filters['status'] === 'active');
        }

        if (!empty($filters['search'])) {
            $search = $filters['search'];
            $query->whereHas('student', function ($q) use ($search) {
                $q->where('first_name', 'like', "%{$search}%")
                  ->orWhere('last_name', 'like', "%{$search}%")
                  ->orWhere('student_id', 'like', "%{$search}%")
                  ->orWhereHas('user', function ($userQuery) use ($search) {
                      $userQuery->where('email', 'like', "%{$search}%");
                  });
            });
        }

        if (!empty($filters['enrolled_from'])) {
            $query->where('enrolled_at', '>=', $filters['enrolled_from']);
        }

        if (!empty($filters['enrolled_to'])) {
            $query->where('enrolled_at', '<=', $filters['enrolled_to']);
        }

        return $query->latest('enrolled_at')->paginate(20);
    }

    /**
     * Create a new enrollment
     */
    public function createEnrollment(array $data): Enrollment
    {
        // Validate that student is not already enrolled in the same classroom for the academic year
        $existingEnrollment = Enrollment::where('student_id', $data['student_id'])
            ->where('classroom_id', $data['classroom_id'])
            ->where('academic_year_id', $data['academic_year_id'])
            ->where('is_active', true)
            ->first();

        if ($existingEnrollment) {
            throw new \Exception('Student is already enrolled in this classroom for the academic year.');
        }

        // Check classroom capacity
        $classroom = Classroom::findOrFail($data['classroom_id']);
        $currentEnrollments = $classroom->enrollments()
            ->where('academic_year_id', $data['academic_year_id'])
            ->where('is_active', true)
            ->count();

        if ($classroom->capacity && $currentEnrollments >= $classroom->capacity) {
            throw new \Exception('Classroom has reached its maximum capacity.');
        }

        // Create enrollment
        $enrollment = Enrollment::create([
            'student_id' => $data['student_id'],
            'classroom_id' => $data['classroom_id'],
            'academic_year_id' => $data['academic_year_id'],
            'enrolled_at' => $data['enrolled_at'] ?? now(),
            'is_active' => true,
        ]);

        return $enrollment->load(['student.user', 'classroom', 'academicYear']);
    }

    /**
     * Update enrollment
     */
    public function updateEnrollment(Enrollment $enrollment, array $data): Enrollment
    {
        // If changing classroom or academic year, validate no conflicts
        if (isset($data['classroom_id']) || isset($data['academic_year_id'])) {
            $classroomId = $data['classroom_id'] ?? $enrollment->classroom_id;
            $academicYearId = $data['academic_year_id'] ?? $enrollment->academic_year_id;

            $existingEnrollment = Enrollment::where('student_id', $enrollment->student_id)
                ->where('classroom_id', $classroomId)
                ->where('academic_year_id', $academicYearId)
                ->where('id', '!=', $enrollment->id)
                ->where('is_active', true)
                ->first();

            if ($existingEnrollment) {
                throw new \Exception('Student is already enrolled in this classroom for the academic year.');
            }

            // Check classroom capacity if changing classroom
            if (isset($data['classroom_id']) && $data['classroom_id'] != $enrollment->classroom_id) {
                $classroom = Classroom::findOrFail($data['classroom_id']);
                $currentEnrollments = $classroom->enrollments()
                    ->where('academic_year_id', $academicYearId)
                    ->where('is_active', true)
                    ->count();

                if ($classroom->capacity && $currentEnrollments >= $classroom->capacity) {
                    throw new \Exception('Target classroom has reached its maximum capacity.');
                }
            }
        }

        $enrollment->update($data);

        return $enrollment->load(['student.user', 'classroom', 'academicYear']);
    }

    /**
     * Transfer student to different classroom
     */
    public function transferStudent(int $studentId, int $newClassroomId, int $academicYearId, string $reason = null): Enrollment
    {
        $student = Student::findOrFail($studentId);

        // Find current active enrollment
        $currentEnrollment = $student->enrollments()
            ->where('academic_year_id', $academicYearId)
            ->where('is_active', true)
            ->first();

        if (!$currentEnrollment) {
            throw new \Exception('No active enrollment found for this student in the academic year.');
        }

        if ($currentEnrollment->classroom_id == $newClassroomId) {
            throw new \Exception('Student is already enrolled in the target classroom.');
        }

        // Check new classroom capacity
        $newClassroom = Classroom::findOrFail($newClassroomId);
        $currentEnrollments = $newClassroom->enrollments()
            ->where('academic_year_id', $academicYearId)
            ->where('is_active', true)
            ->count();

        if ($newClassroom->capacity && $currentEnrollments >= $newClassroom->capacity) {
            throw new \Exception('Target classroom has reached its maximum capacity.');
        }

        DB::beginTransaction();
        try {
            // Deactivate current enrollment
            $currentEnrollment->update([
                'is_active' => false,
                'transfer_reason' => $reason,
                'transferred_at' => now(),
            ]);

            // Create new enrollment
            $newEnrollment = Enrollment::create([
                'student_id' => $studentId,
                'classroom_id' => $newClassroomId,
                'academic_year_id' => $academicYearId,
                'enrolled_at' => now(),
                'is_active' => true,
                'previous_enrollment_id' => $currentEnrollment->id,
            ]);

            DB::commit();

            return $newEnrollment->load(['student.user', 'classroom', 'academicYear']);

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

    /**
     * Bulk enroll students
     */
    public function bulkEnrollStudents(array $studentIds, int $classroomId, int $academicYearId): array
    {
        $classroom = Classroom::findOrFail($classroomId);
        $results = ['success' => 0, 'errors' => []];

        // Check classroom capacity
        $currentEnrollments = $classroom->enrollments()
            ->where('academic_year_id', $academicYearId)
            ->where('is_active', true)
            ->count();

        $availableSlots = $classroom->capacity ? ($classroom->capacity - $currentEnrollments) : count($studentIds);

        if ($classroom->capacity && count($studentIds) > $availableSlots) {
            throw new \Exception("Classroom only has {$availableSlots} available slots, but {count($studentIds)} students were selected.");
        }

        DB::beginTransaction();
        try {
            foreach ($studentIds as $studentId) {
                try {
                    // Check if already enrolled
                    $existingEnrollment = Enrollment::where('student_id', $studentId)
                        ->where('classroom_id', $classroomId)
                        ->where('academic_year_id', $academicYearId)
                        ->where('is_active', true)
                        ->first();

                    if ($existingEnrollment) {
                        $student = Student::find($studentId);
                        $results['errors'][] = "Student {$student->full_name} is already enrolled in this classroom.";
                        continue;
                    }

                    // Create enrollment
                    Enrollment::create([
                        'student_id' => $studentId,
                        'classroom_id' => $classroomId,
                        'academic_year_id' => $academicYearId,
                        'enrolled_at' => now(),
                        'is_active' => true,
                    ]);

                    $results['success']++;

                } catch (\Exception $e) {
                    $student = Student::find($studentId);
                    $results['errors'][] = "Failed to enroll {$student->full_name}: {$e->getMessage()}";
                }
            }

            DB::commit();
            return $results;

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

    /**
     * Get enrollment statistics
     */
    public function getEnrollmentStatistics(int $academicYearId = null): array
    {
        $query = Enrollment::query();

        if ($academicYearId) {
            $query->where('academic_year_id', $academicYearId);
        }

        $totalEnrollments = $query->count();
        $activeEnrollments = $query->where('is_active', true)->count();
        $inactiveEnrollments = $totalEnrollments - $activeEnrollments;

        // Enrollments by classroom
        $enrollmentsByClassroom = $query->where('is_active', true)
            ->with('classroom')
            ->get()
            ->groupBy('classroom_id')
            ->map(function ($enrollments) {
                $classroom = $enrollments->first()->classroom;
                return [
                    'classroom_name' => $classroom->name,
                    'count' => $enrollments->count(),
                    'capacity' => $classroom->capacity,
                    'utilization' => $classroom->capacity ? round(($enrollments->count() / $classroom->capacity) * 100, 2) : null,
                ];
            });

        // Recent enrollments (last 30 days)
        $recentEnrollments = Enrollment::where('enrolled_at', '>=', now()->subDays(30))
            ->where('is_active', true)
            ->count();

        return [
            'total_enrollments' => $totalEnrollments,
            'active_enrollments' => $activeEnrollments,
            'inactive_enrollments' => $inactiveEnrollments,
            'recent_enrollments' => $recentEnrollments,
            'enrollments_by_classroom' => $enrollmentsByClassroom,
        ];
    }

    /**
     * Get available students for enrollment
     */
    public function getAvailableStudents(int $classroomId, int $academicYearId): \Illuminate\Database\Eloquent\Collection
    {
        // Get students who are not enrolled in any classroom for the academic year
        return Student::where('is_active', true)
            ->whereDoesntHave('enrollments', function ($query) use ($academicYearId) {
                $query->where('academic_year_id', $academicYearId)
                      ->where('is_active', true);
            })
            ->with('user')
            ->orderBy('first_name')
            ->get();
    }

    /**
     * Get enrollment history for a student
     */
    public function getStudentEnrollmentHistory(int $studentId): \Illuminate\Database\Eloquent\Collection
    {
        return Enrollment::where('student_id', $studentId)
            ->with(['classroom', 'academicYear'])
            ->orderBy('enrolled_at', 'desc')
            ->get();
    }

    /**
     * Deactivate enrollment
     */
    public function deactivateEnrollment(Enrollment $enrollment, string $reason = null): Enrollment
    {
        $enrollment->update([
            'is_active' => false,
            'deactivated_at' => now(),
            'deactivation_reason' => $reason,
        ]);

        return $enrollment;
    }

    /**
     * Reactivate enrollment
     */
    public function reactivateEnrollment(Enrollment $enrollment): Enrollment
    {
        // Check if student is already enrolled in another classroom for the same academic year
        $existingEnrollment = Enrollment::where('student_id', $enrollment->student_id)
            ->where('academic_year_id', $enrollment->academic_year_id)
            ->where('id', '!=', $enrollment->id)
            ->where('is_active', true)
            ->first();

        if ($existingEnrollment) {
            throw new \Exception('Student is already enrolled in another classroom for this academic year.');
        }

        // Check classroom capacity
        $classroom = $enrollment->classroom;
        $currentEnrollments = $classroom->enrollments()
            ->where('academic_year_id', $enrollment->academic_year_id)
            ->where('is_active', true)
            ->count();

        if ($classroom->capacity && $currentEnrollments >= $classroom->capacity) {
            throw new \Exception('Classroom has reached its maximum capacity.');
        }

        $enrollment->update([
            'is_active' => true,
            'reactivated_at' => now(),
            'deactivated_at' => null,
            'deactivation_reason' => null,
        ]);

        return $enrollment;
    }
}
