import json

from django import forms
from django.contrib import admin

from schools.access import get_user_school
from schools.cbe import JUNIOR_SUBJECT_SPECS, LOWER_PRIMARY_SUBJECT_SPECS, UPPER_PRIMARY_SUBJECT_SPECS

from .models import Subject, StudentPathway, Exam, Mark, Attendance, SyllabusDocument


CBE_SUBJECT_CHOICES = [
    ("Lower Primary", sorted({spec["name"] for spec in LOWER_PRIMARY_SUBJECT_SPECS})),
    ("Upper Primary", sorted({spec["name"] for spec in UPPER_PRIMARY_SUBJECT_SPECS})),
    ("Junior", sorted({spec["name"] for spec in JUNIOR_SUBJECT_SPECS})),
]

CAMBRIDGE_PRIMARY_SUBJECTS = [
    "Art & Design",
    "Computing",
    "Digital Literacy",
    "English",
    "English as a Second Language",
    "Global Perspectives",
    "Humanities",
    "Mathematics",
    "Modern Foreign Language",
    "Music",
    "Physical Education",
    "Science",
    "Wellbeing",
]

CAMBRIDGE_LOWER_SECONDARY_SUBJECTS = [
    "Art & Design",
    "Computing",
    "Digital Literacy",
    "English",
    "English as a Second Language",
    "Global Perspectives",
    "Humanities",
    "Mathematics",
    "Modern Foreign Language",
    "Music",
    "Physical Education",
    "Science",
    "Wellbeing",
]

CAMBRIDGE_IGCSE_SUBJECTS = [
    "Accounting",
    "Accounting (9-1)",
    "Afrikaans - Second Language",
    "Agriculture",
    "Arabic - First Language",
    "Arabic - First Language (9-1)",
    "Arabic - Foreign Language",
    "Arabic (9-1)",
    "Art & Design",
    "Art & Design (9-1)",
    "Bahasa Indonesia",
    "Biology",
    "Biology (9-1)",
    "Business Studies",
    "Business Studies (9-1)",
    "Chemistry",
    "Chemistry (9-1)",
    "Chinese - First Language",
    "Chinese - Second Language",
    "Chinese (Mandarin) - Foreign Language",
    "Chinese (Mandarin) (9-1)",
    "Classical Greek",
    "Combined Science",
    "Computer Science",
    "Computer Science (9-1)",
    "Co-ordinated Sciences (Double)",
    "Co-ordinated Sciences (9-1)",
    "Design & Technology",
    "Design & Technology (9-1)",
    "Drama",
    "Drama (9-1)",
    "Economics",
    "Economics (9-1)",
    "English",
    "English (as an Additional Language)",
    "English as a Second Language",
    "English as a Second Language (9-1)",
    "English - First Language",
    "English - First Language (9-1)",
    "English Literature",
    "English Literature (9-1)",
    "Enterprise",
    "Environmental Management",
    "Food & Nutrition",
    "French - Foreign Language",
    "French - Foreign Language (9-1)",
    "Geography",
    "Geography (9-1)",
    "German - Foreign Language",
    "German - Foreign Language (9-1)",
    "Global Perspectives",
    "Greek - Foreign Language",
    "Hindi as a Second Language",
    "History",
    "History (9-1)",
    "Information and Communication Technology",
    "Islamic Studies",
    "Islamiyat",
    "Italian - Foreign Language",
    "Japanese - Foreign Language",
    "Latin",
    "Literature (English)",
    "Malay - First Language",
    "Malay - Foreign Language",
    "Marine Science",
    "Mathematics",
    "Mathematics - Additional",
    "Mathematics - International",
    "Mathematics (9-1)",
    "Mathematics (US)",
    "Music",
    "Music (9-1)",
    "Pakistan Studies",
    "Physical Education",
    "Physical Education (9-1)",
    "Physical Science",
    "Physics",
    "Physics (9-1)",
    "Portuguese - First Language",
    "Psychology",
    "Religious Studies",
    "Sanskrit",
    "Science - Combined",
    "Setswana - First Language",
    "Sociology",
    "Spanish - First Language",
    "Spanish - Foreign Language",
    "Spanish - Literature in Spanish",
    "Spanish (9-1)",
    "Statistics",
    "Swahili",
    "Thai - First Language",
    "Travel & Tourism",
    "Turkish - First Language",
    "Urdu as a Second Language",
    "Vietnamese - First Language",
    "World Literature",
]

CAMBRIDGE_AS_A_SUBJECTS = [
    "Accounting",
    "Afrikaans - Language (AS Level only)",
    "Arabic",
    "Arabic - Language (AS Level only)",
    "Art & Design",
    "Biblical Studies",
    "Biology",
    "Business",
    "Chemistry",
    "Chinese - Language & Literature (A Level only)",
    "Chinese Language (AS Level only)",
    "Classical Studies",
    "Computer Science",
    "Design & Technology",
    "Digital Media & Design",
    "Drama",
    "Economics",
    "English - Language",
    "English General Paper (AS Level only)",
    "English Language & Literature",
    "English Literature",
    "Environmental Management",
    "Food Studies (AS Level only)",
    "French",
    "Geography",
    "German",
    "Global Perspectives & Research",
    "Hindi",
    "History",
    "Information Technology",
    "Islamic Studies",
    "Japanese Language (AS Level only)",
    "Law",
    "Literature in English",
    "Marine Science (AS Level only)",
    "Mathematics",
    "Mathematics - Further",
    "Media Studies",
    "Music",
    "Nepal Studies (AS Level only)",
    "Physical Education",
    "Physics",
    "Portuguese",
    "Psychology",
    "Sociology",
    "Spanish",
    "Thinking Skills (AS Level only)",
    "Travel & Tourism",
    "Urdu - Language (AS Level only)",
]

CAMBRIDGE_SUBJECT_CHOICES = [
    ("Cambridge Primary", sorted(CAMBRIDGE_PRIMARY_SUBJECTS)),
    ("Cambridge Lower Secondary", sorted(CAMBRIDGE_LOWER_SECONDARY_SUBJECTS)),
    ("Cambridge Upper Secondary (IGCSE)", sorted(CAMBRIDGE_IGCSE_SUBJECTS)),
    ("Cambridge Advanced (AS & A Level)", sorted(CAMBRIDGE_AS_A_SUBJECTS)),
]

CBE_CLASS_CHOICES = [
    ("Pre School", ["Pre School", "Pre-Primary 1 (PP1)", "Pre-Primary 2 (PP2)"]),
    ("Lower Primary", ["Grade 1", "Grade 2", "Grade 3"]),
    ("Upper Primary", ["Grade 4", "Grade 5", "Grade 6"]),
    ("Junior", ["Grade 7", "Grade 8", "Grade 9"]),
    ("Senior", ["Grade 10", "Grade 11", "Grade 12"]),
]

CAMBRIDGE_CLASS_CHOICES = [
    ("Cambridge Primary", ["Year 1", "Year 2", "Year 3", "Year 4", "Year 5", "Year 6"]),
    ("Cambridge Lower Secondary", ["Year 7", "Year 8", "Year 9"]),
    ("Cambridge Upper Secondary (IGCSE)", ["Year 10", "Year 11"]),
    ("Cambridge Advanced (AS & A Level)", ["Year 12", "Year 13"]),
]


def _grouped_choices(groups):
    return [(label, [(item, item) for item in items]) for label, items in groups]

def _curriculum_key(value: str) -> str:
    val = (value or "").strip().upper()
    if val == "CAMBRIDGE":
        return "cambridge"
    if val == "CBE":
        return "cbe"
    return ""


def _choices_for(curriculum_key: str, subject: bool = True):
    if curriculum_key == "cambridge":
        return _grouped_choices(CAMBRIDGE_SUBJECT_CHOICES if subject else CAMBRIDGE_CLASS_CHOICES)
    return _grouped_choices(CBE_SUBJECT_CHOICES if subject else CBE_CLASS_CHOICES)


class SyllabusDocumentAdminForm(forms.ModelForm):
    subject_name_choice = forms.ChoiceField(choices=[("", "---------")], required=False)
    class_name_choice = forms.ChoiceField(choices=[("", "---------")], required=False)

    class Meta:
        model = SyllabusDocument
        fields = "__all__"

    def __init__(self, *args, **kwargs):
        self.request = kwargs.pop("request", None)
        super().__init__(*args, **kwargs)
        self.fields.pop("subject_name", None)
        self.fields.pop("class_name", None)
        if self.request and self.request.user and self.request.user.is_superuser:
            if "subject" in self.fields:
                self.fields["subject"].required = False
            if "classroom" in self.fields:
                self.fields["classroom"].required = False

            curriculum_val = ""
            if self.data.get("curriculum_type"):
                curriculum_val = self.data.get("curriculum_type", "")
            elif getattr(self.instance, "curriculum_type", ""):
                curriculum_val = self.instance.curriculum_type
            curriculum_key = _curriculum_key(curriculum_val) or "cbe"

            self.fields["subject_name_choice"].choices = [("", "---------")] + _choices_for(curriculum_key, subject=True)
            self.fields["class_name_choice"].choices = [("", "---------")] + _choices_for(curriculum_key, subject=False)

            self.fields["subject_name_choice"].widget.attrs["data-cbe"] = json.dumps(_grouped_choices(CBE_SUBJECT_CHOICES))
            self.fields["subject_name_choice"].widget.attrs["data-cambridge"] = json.dumps(_grouped_choices(CAMBRIDGE_SUBJECT_CHOICES))
            self.fields["class_name_choice"].widget.attrs["data-cbe"] = json.dumps(_grouped_choices(CBE_CLASS_CHOICES))
            self.fields["class_name_choice"].widget.attrs["data-cambridge"] = json.dumps(_grouped_choices(CAMBRIDGE_CLASS_CHOICES))
        else:
            self.fields.pop("subject_name_choice", None)
            self.fields.pop("class_name_choice", None)

    def clean(self):
        cleaned = super().clean()
        user = getattr(self.request, "user", None)
        if user and user.is_superuser:
            subject_choice = (cleaned.get("subject_name_choice") or "").strip()
            class_choice = (cleaned.get("class_name_choice") or "").strip()
            if subject_choice:
                cleaned["subject_name"] = subject_choice
            if class_choice:
                cleaned["class_name"] = class_choice
        return cleaned


@admin.register(Subject)
class AcademicSubjectAdmin(admin.ModelAdmin):
	list_display = ('name', 'school', 'education_level', 'pathway')
	list_filter = ('school', 'education_level', 'pathway')
	search_fields = ('name', 'short_name')


@admin.register(StudentPathway)
class StudentPathwayAdmin(admin.ModelAdmin):
	list_display = ('student', 'pathway')
	list_filter = ('pathway',)
	search_fields = ('student__first_name', 'student__last_name', 'student__admission_number')


@admin.register(Exam)
class AcademicExamAdmin(admin.ModelAdmin):
	list_display = ('classroom', 'term', 'year', 'school')
	list_filter = ('term', 'year', 'school')


@admin.register(Mark)
class MarkAdmin(admin.ModelAdmin):
	list_display = ('student', 'subject', 'score', 'exam')
	list_filter = ('exam__year', 'exam__term', 'student__school')
	search_fields = ('student__first_name', 'student__last_name', 'subject__name')


@admin.register(Attendance)
class AttendanceAdmin(admin.ModelAdmin):
	list_display = ('student', 'date', 'present')
	list_filter = ('date', 'present')
	search_fields = ('student__first_name', 'student__last_name', 'student__admission_number')


@admin.register(SyllabusDocument)
class SyllabusDocumentAdmin(admin.ModelAdmin):
	form = SyllabusDocumentAdminForm
	list_display = ('title', 'curriculum_type', 'subject_name', 'class_name', 'subject', 'classroom', 'education_level', 'uploaded_at')
	list_filter = ('curriculum_type', 'education_level')
	search_fields = ('title', 'subject__name', 'subject_name', 'class_name')

	class Media:
		js = ("js/syllabus_admin.js",)

	def get_form(self, request, obj=None, **kwargs):
		form = super().get_form(request, obj, **kwargs)

		class FormWithRequest(form):
			def __init__(self, *args, **form_kwargs):
				form_kwargs["request"] = request
				super().__init__(*args, **form_kwargs)

		return FormWithRequest

	def get_fieldsets(self, request, obj=None):
		if request.user.is_superuser:
			return (
				(None, {
					'fields': (
						'title',
						'curriculum_type',
						'subject_name_choice',
						'class_name_choice',
						'education_level',
						'document',
						'sample_scheme',
						'sample_lesson_plan',
					)
				}),
			)
		return (
			(None, {
				'fields': (
					'title',
					'curriculum_type',
					'subject',
					'classroom',
					'education_level',
					'document',
					'sample_scheme',
					'sample_lesson_plan',
				)
			}),
		)
	def formfield_for_foreignkey(self, db_field, request, **kwargs):
		if request.user.is_superuser:
			return super().formfield_for_foreignkey(db_field, request, **kwargs)
		school = get_user_school(request.user)
		if db_field.name == "subject" and school:
			kwargs["queryset"] = Subject.objects.filter(school=school).order_by("name")
		if db_field.name == "classroom" and school:
			kwargs["queryset"] = school.classes.order_by("order", "name")
		return super().formfield_for_foreignkey(db_field, request, **kwargs)

	def save_model(self, request, obj, form, change):
		if request.user.is_superuser:
			if form.cleaned_data.get('subject_name_choice'):
				obj.subject_name = form.cleaned_data['subject_name_choice']
			if form.cleaned_data.get('class_name_choice'):
				obj.class_name = form.cleaned_data['class_name_choice']
		if getattr(obj, 'subject', None) and not obj.subject_name:
			obj.subject_name = obj.subject.name
		if getattr(obj, 'classroom', None) and not obj.class_name:
			obj.class_name = obj.classroom.name
		super().save_model(request, obj, form, change)
