from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from django.db.models import Q
from classroom.models import Classroom
from status.models import Status
from departments.models import Department
from batch.models import Batch
from batch_year.models import BatchYear
from semester.models import Semester
from teacher_management.models import Teacher
from course.models import Course
from days.models import Day
from timeslot.models import TimeSlot
import json
import os
from django.conf import settings
from settings.models import AppSettings
from status.serializers import StatusSerializer

@api_view(['GET'])
@permission_classes([IsAuthenticated])
def get_status_data(request):
    use_cache = AppSettings.get_setting('use_cache', default=False)
    if use_cache:
        try:
            with open(os.path.join(settings.DATA_CACHE_DIR, 'status.json'), 'r') as f:
                data = json.load(f)
            return Response(data)
        except FileNotFoundError:
            # If cache is not found, fallback to database
            pass
    
    statuses = Status.objects.all()
    serializer = StatusSerializer(statuses, many=True)
    
    # Format the data to match status.json structure
    formatted_data = {}
    for status_item in serializer.data:
        status_type = status_item.get('type')
        if status_type:
            if status_type not in formatted_data:
                formatted_data[status_type] = []
            formatted_data[status_type].append(status_item)
            
    return Response(formatted_data)


@api_view(['GET'])
@permission_classes([IsAuthenticated])
def get_classrooms(request):
    use_cache = AppSettings.get_setting('use_cache', default=False)
    if use_cache:
        try:
            with open(os.path.join(settings.DATA_CACHE_DIR, 'classrooms.json'), 'r') as f:
                data = json.load(f)
            return Response(data)
        except FileNotFoundError:
            # If cache is not found, fallback to database
            pass

    classrooms = Classroom.objects.all()
    data = []
    for classroom in classrooms:
        data.append({
            'name': f'Room - {classroom.room_number}',
            'code': classroom.room_number,
            'id': classroom.classroom_id
        })
    return Response(data)

def _read_cache_file(filename):
    """Helper to read a cache file."""
    try:
        cache_file = os.path.join(settings.DATA_CACHE_DIR, filename)
        with open(cache_file, 'r') as f:
            return json.load(f)
    except (FileNotFoundError, json.JSONDecodeError):
        return []

def _get_use_cache(request):
    """Get use_cache parameter from request, default to 0 (database)"""
    use_cache = request.query_params.get('use_cache', '0')
    try:
        return int(use_cache)
    except (ValueError, TypeError):
        return 0

def _serialize_department_for_cache(department):
    """Serialize department to match cache file format"""
    return {
        "department_id": department.department_id,
        "department_name": department.department_name,
        "slug": department.slug,
        "department_code": department.department_code,
        "status": department.status.title if department.status else "Active",
        "created_at": department.created_at.isoformat() if department.created_at else None
    }

def _get_departments_from_db(organization=None):
    """Get departments from database in cache format"""
    query = Q()
    if organization:
        query = Q(organization=organization) | Q(is_global=True)
    else:
        query = Q(is_global=True)
    departments = Department.objects.select_related('status').filter(query).all()
    return [_serialize_department_for_cache(dept) for dept in departments]

def _serialize_batch_for_cache(batch):
    """Serialize batch to match cache file format"""
    return {
        "batch_id": batch.batch_id,
        "batch_name": batch.batch_name,
        "slug": batch.slug,
        "department": batch.department.department_name if batch.department else None,
        "department_id": batch.department.department_id if batch.department else None,
        "start_year": batch.start_year,
        "end_year": batch.end_year,
        "advisor": f"{batch.advisor.first_name} {batch.advisor.last_name}" if batch.advisor else None,
        "advisor_id": batch.advisor.teacher_id if batch.advisor else None,
        "status": batch.status.title if batch.status else "Active"
    }

def _get_batches_from_db(organization=None):
    """Get batches from database in cache format"""
    query = Q()
    if organization:
        query = Q(organization=organization) | Q(is_global=True)
    else:
        query = Q(is_global=True)
    batches = Batch.objects.select_related('department', 'advisor', 'status').filter(query).all()
    return [_serialize_batch_for_cache(batch) for batch in batches]

def _serialize_year_for_cache(year):
    """Serialize year to match cache file format"""
    return {
        "year_id": year.year_id,
        "title": year.title,
        "slug": year.slug,
        "code": year.code,
        "created_at": year.created_at.isoformat() if year.created_at else None,
        "year_name": year.title
    }

def _get_years_from_db(organization=None):
    """Get years from database in cache format"""
    query = Q()
    if organization:
        query = Q(organization=organization) | Q(is_global=True)
    else:
        query = Q(is_global=True)
    years = BatchYear.objects.filter(query).all()
    return [_serialize_year_for_cache(year) for year in years]

def _serialize_semester_for_cache(semester):
    """Serialize semester to match cache file format"""
    return {
        "semester_id": semester.semester_id,
        "title": semester.title,
        "slug": semester.slug,
        "code": semester.code,
        "semester_name": semester.title,
        "semester_code": semester.code
    }

def _get_semesters_from_db(organization=None):
    """Get semesters from database in cache format"""
    query = Q()
    if organization:
        query = Q(organization=organization) | Q(is_global=True)
    else:
        query = Q(is_global=True)
    semesters = Semester.objects.filter(query).all()
    return [_serialize_semester_for_cache(semester) for semester in semesters]

def _serialize_teacher_for_cache(teacher):
    """Serialize teacher to match cache file format"""
    return {
        "teacher_id": teacher.teacher_id,
        "first_name": teacher.first_name,
        "last_name": teacher.last_name,
        "name": f"{teacher.first_name} {teacher.last_name or ''}".strip(),
        "code": teacher.code,
        "slug": teacher.slug,
        "email": teacher.email,
        "phone": teacher.phone,
        "department": teacher.department.department_name if teacher.department else None,
        "hire_date": teacher.hire_date.isoformat() if teacher.hire_date else None,
        "status": teacher.status.title if teacher.status else "Active"
    }

def _get_teachers_from_db(organization=None):
    """Get teachers from database in cache format"""
    query = Q()
    if organization:
        query = Q(organization=organization)
    teachers = Teacher.objects.select_related('department', 'status').filter(query).all()
    return [_serialize_teacher_for_cache(teacher) for teacher in teachers]

def _serialize_classroom_for_cache(classroom):
    """Serialize classroom to match cache file format"""
    return {
        "classroom_id": classroom.classroom_id,
        "room_number": classroom.room_number,
        "slug": classroom.slug,
        "building": classroom.building,
        "capacity": classroom.capacity,
        "status": classroom.status.title if classroom.status else "Available"
    }

def _get_classrooms_from_db(organization=None):
    """Get classrooms from database in cache format"""
    query = Q()
    if organization:
        query = Q(organization=organization) | Q(is_global=True)
    else:
        query = Q(is_global=True)
    classrooms = Classroom.objects.select_related('status').filter(query).all()
    return [_serialize_classroom_for_cache(classroom) for classroom in classrooms]

def _serialize_course_for_cache(course):
    """Serialize course to match cache file format"""
    teachers_data = []
    for teacher in course.teachers.all():
        teacher_data = {
            "first_name": teacher.first_name,
            "last_name": teacher.last_name,
            "code": teacher.code,
            "slug": teacher.slug,
            "department": {
                "department_name": teacher.department.department_name if teacher.department else None,
                "slug": teacher.department.slug if teacher.department else None,
                "department_code": teacher.department.department_code if teacher.department else None,
                "head_teacher": None,
                "status": {
                    "title": teacher.department.status.title if teacher.department and teacher.department.status else None,
                    "slug": teacher.department.status.slug if teacher.department and teacher.department.status else None,
                    "type": teacher.department.status.type if teacher.department and teacher.department.status else None,
                    "description": ""
                },
                "created_at": teacher.department.created_at.isoformat() if teacher.department and teacher.department.created_at else None
            },
            "email": teacher.email,
            "phone": teacher.phone,
            "hire_date": teacher.hire_date.isoformat() if teacher.hire_date else None,
            "status": teacher.status.title if teacher.status else "Active"
        }
        teachers_data.append(teacher_data)
    
    return {
        "id": course.id,
        "name": course.name,
        "code": course.code,
        "slug": course.slug,
        "credit": str(course.credit) if course.credit else None,
        "credit_hours": str(course.credit_hours) if course.credit_hours else None,
        "created_at": course.created_at.isoformat() if course.created_at else None,
        "updated_at": course.updated_at.isoformat() if course.updated_at else None,
        "teachers": teachers_data,
        "course_name": course.name,
        "course_code": course.code,
        "credits": float(course.credit) if course.credit else 0.0
    }

def _get_courses_from_db(organization=None):
    """Get courses from database in cache format"""
    query = Q()
    if organization:
        query = Q(organization=organization) | Q(is_global=True)
    else:
        query = Q(is_global=True)
    courses = Course.objects.prefetch_related('teachers__department__status', 'teachers__status').filter(query).all()
    return [_serialize_course_for_cache(course) for course in courses]

def _serialize_day_for_cache(day):
    """Serialize day to match cache file format"""
    return {
        "id": str(day.id),
        "name": day.name,
        "slug": day.slug,
        "status": day.status.title if day.status else "Available",
        "created_at": day.created_at.isoformat() if day.created_at else None,
        "day_name": day.name
    }

def _get_days_from_db(organization=None):
    """Get days from database in cache format"""
    query = Q()
    if organization:
        query = Q(organization=organization) | Q(is_global=True)
    else:
        query = Q(is_global=True)
    days = Day.objects.filter(query).all()
    return [_serialize_day_for_cache(day) for day in days]

def _serialize_timeslot_for_cache(timeslot):
    """Serialize timeslot to match cache file format"""
    return {
        "id": str(timeslot.id),
        "start_time": timeslot.start_time.strftime("%H:%M:%S") if timeslot.start_time else None,
        "end_time": timeslot.end_time.strftime("%H:%M:%S") if timeslot.end_time else None,
        "slot_name": timeslot.slot_name,
        "slug": timeslot.slug,
        "status": timeslot.status.title if timeslot.status else "Available",
        "created_at": timeslot.created_at.isoformat() if timeslot.created_at else None
    }

def _get_timeslots_from_db(organization=None):
    """Get timeslots from database in cache format"""
    query = Q(is_active=True)
    if organization:
        query &= (Q(organization=organization) | Q(is_global=True))
    else:
        query &= Q(is_global=True)
    timeslots = TimeSlot.objects.select_related('status').filter(query).all()
    return [_serialize_timeslot_for_cache(timeslot) for timeslot in timeslots]
    
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def form_data(request):
    """Get all data needed for routine form"""
    use_cache = _get_use_cache(request)
    
    if use_cache == 1:
        # Read from cache files
        data = {
            "teachers": _read_cache_file('teachers.json'),
            "classrooms": _read_cache_file('classrooms.json'),
            "departments": _read_cache_file('departments.json'),
            "batches": _read_cache_file('batches.json'),
            "years": _read_cache_file('batch_year.json'),
            "semesters": _read_cache_file('semesters.json'),
            "days": _read_cache_file('days.json'),
            "timeslots": _read_cache_file('timeslots.json'),
        }
    else:
        # Read from database
        data = {
            "teachers": _get_teachers_from_db(),
            "classrooms": _get_classrooms_from_db(),
            "departments": _get_departments_from_db(),
            "batches": _get_batches_from_db(),
            "years": _get_years_from_db(),
            "semesters": _get_semesters_from_db(),
            "days": _get_days_from_db(),
            "timeslots": _get_timeslots_from_db(),
        }
        
    enable_image_processing = AppSettings.get_setting('enable_image_processing', default=True)
    if isinstance(enable_image_processing, str):
        data["enable_image_processing"] = enable_image_processing.lower() == 'true'
    else:
        data["enable_image_processing"] = bool(enable_image_processing)

    return Response(data)
