# -*- coding: UTF-8 -*-
# Copyright 2024-2025 Rumma & Ko Ltd
# License: GNU Affero General Public License v3 (see file COPYING for details)

from decimal import Decimal
from django.db import models
from django.conf import settings
from django.utils.html import format_html, mark_safe
from django.utils.text import format_lazy
from django.core.exceptions import ValidationError
from lino.utils.html import E, tostring, join_elems
from lino.utils.mldbc.mixins import BabelDesignated
from lino.modlib.users.mixins import UserAuthored, My
from lino.modlib.printing.mixins import CachedPrintable, DirectPrintAction
from lino.mixins import Referrable, Sequenced, Created
from lino_prima.lib.ratings.choicelists import RatingTypes
from lino.api import dd, rt, pgettext, _


class Grade(Referrable, BabelDesignated):  # hard-coded list in zeugnisse
    class Meta:
        verbose_name = _("Grade")  # Jahrgangsstufe, Schulstufe
        verbose_name_plural = _("Grades")
        abstract = dd.is_abstract_model(__name__, 'Grade')

    cert_template = dd.ForeignKey(
        'cert.CertTemplate', blank=True, null=True)

class Subject(BabelDesignated, Sequenced):
    class Meta:
        verbose_name = pgettext("in school", "Subject")
        verbose_name_plural = _("Subjects")
        abstract = dd.is_abstract_model(__name__, 'Subject')
    advanced = dd.BooleanField(_("Advanced"), default=False)
    icon_text = dd.CharField(_("Icon"), max_length=5, blank=True, null=True)
    rating_type = RatingTypes.field(blank=True, null=True)
    image_file = dd.ForeignKey('uploads.Upload',
        verbose_name=_("Image"), blank=True, null=True)


class Skill(BabelDesignated, Sequenced):
    class Meta:
        verbose_name = _("Skill")
        verbose_name_plural = _("Skills")
        abstract = dd.is_abstract_model(__name__, 'Skill')
    subject = dd.ForeignKey('prima.Subject')
    with_exams = dd.BooleanField(_("With final exams"))  # Mit Abschlusstests

    # def __str__(self):
    #     return f"{self.subject}:{super().__str__()}"

    def get_siblings(self):
        return self.__class__.objects.filter(subject=self.subject)



class Group(BabelDesignated):  # zeugnisse.Klasse
    class Meta:
        verbose_name = _("Group")
        verbose_name_plural = _("Groups")
        abstract = dd.is_abstract_model(__name__, 'Group')
        ordering = ['designation']
    grade = dd.ForeignKey('prima.Grade')
    year = dd.ForeignKey('periods.StoredYear', blank=True)

    @classmethod
    def get_simple_parameters(cls):
        yield super().get_simple_parameters()
        yield 'year'

    @classmethod
    def param_defaults(cls, ar, **kw):
        kw = super().param_defaults(ar, **kw)
        kw.update(year=rt.models.periods.StoredYear.get_or_create_from_date(
            dd.today()))
        return kw

    def full_clean(self, *args, **kwargs):
        if self.year_id is None:
            self.year = rt.models.periods.StoredYear.get_or_create_from_date(dd.today())
        super().full_clean(*args, **kwargs)

    def as_paragraph(self, ar, **kwargs):
        s = ar.obj2htmls(self)
        if not ar.is_obvious_field("year"):
            s += format_html(_(" ({year})"), year=str(self.year))
        return mark_safe(s)

    def __str__(self):
        s = super().__str__()
        if not self.year.covers_date(dd.today()):
            s += format_html(_(" ({year})"), year=self.year)
        return mark_safe(s)


class Course(dd.Model):
    class Meta:
        verbose_name = _("Course")
        verbose_name_plural = _("Courses")
        abstract = dd.is_abstract_model(__name__, 'Course')

    group = dd.ForeignKey('prima.Group', related_name='courses')
    subject = dd.ForeignKey('prima.Subject', related_name='courses')

    def __str__(self):
        return _("{subject} in {group}").format(
            subject=self.subject, group=self.group)

    def get_str_words(self, ar):
        if not ar.is_obvious_field("subject"):
            yield str(self.subject)
        if not ar.is_obvious_field("group"):
            yield _("in {group}").format(group=self.group)


class Role(BabelDesignated):
    class Meta:
        verbose_name = _("Role")
        verbose_name_plural = _("Roles")
        abstract = dd.is_abstract_model(__name__, 'Role')


class Cast(UserAuthored):  # zeugnisse.LehrerRolle

    class Meta:
        verbose_name = _("Cast")
        verbose_name_plural = _("Casts")
        abstract = dd.is_abstract_model(__name__, 'Cast')
        # ordering = ['user', 'group__designation', 'subject', 'role']
        ordering = ['user', 'group__designation', 'role']
        unique_together = ['user', 'group', 'role']

    group = dd.ForeignKey('prima.Group')
    # subject = dd.ForeignKey('prima.Subject')
    role = dd.ForeignKey('prima.Role', blank=True, null=True)

    def __str__(self):
        # text = str(self.subject)
        text = _("{teacher}").format(teacher=self.user)
        if self.role is not None:
            text += " " + _("as {role}").format(role=self.role)
        text += " " + _("in {group}").format(group=self.group)
        return text

    def get_str_words(self, ar):
        if self.user != ar.get_user() and not ar.is_obvious_field("user"):
            yield _("{teacher} as").format(teacher=self.user)
        yield str(self.role)
        if not ar.is_obvious_field("group"):
            yield _("in {group}").format(group=self.group)

    @classmethod
    def get_simple_parameters(cls):
        yield super().get_simple_parameters()
        yield 'group__year'

    @classmethod
    def param_defaults(cls, ar, **kw):
        kw = super().param_defaults(ar, **kw)
        kw.update(group__year=rt.models.periods.StoredYear.get_or_create_from_date(
            dd.today()))
        return kw

dd.update_field(Cast, 'user', verbose_name=_("Teacher"))


class Enrolment(dd.Model):
    class Meta:
        verbose_name = _("Enrolment")
        verbose_name_plural = _("Enrolments")
        abstract = dd.is_abstract_model(__name__, 'Enrolment')
    group = dd.ForeignKey('prima.Group')  # , related_name='enrolments')
    pupil = dd.ForeignKey('users.User', verbose_name=_("Pupil"))

    def __str__(self):
        return f"{self.pupil} ({self.group})"

    def get_str_words(self, ar):
        if not ar.is_obvious_field("pupil"):
            yield str(self.pupil)
        if not ar.is_obvious_field("group"):
            yield _("in {group}").format(group=self.group)

    # def as_summary_item(self, ar, text=None):
    #     if text is None:
    #         if ar.is_obvious_field("pupil"):
    #             text = f"{self.group}"
    #         elif ar.is_obvious_field("group"):
    #             text = f"{self.pupil}"
    #         else:
    #             text = str(self)
    #     return super().as_summary_item(ar, text)

    @dd.displayfield(_("Certificates"))
    def certificates(self, ar):
        if ar is None:
            return ''
        Certificate = rt.models.cert.Certificate
        elems = []
        insert_button_attrs = dict(style="text-align: center;")
        sar = rt.models.cert.CertificatesByEnrolment.request(parent=ar, master_instance=self)
        qs = rt.models.periods.StoredPeriod.objects.filter(year=self.group.year)
        for p in qs:
            try:
                crt = Certificate.objects.get(enrolment=self, period=p)
            except Certificate.DoesNotExist:
                btn = sar.gen_insert_button(None, insert_button_attrs,
                        enrolment=str(self), enrolmentHidden=self.pk,
                        period=str(p), periodHidden=p.pk)
                if btn is not None:
                    elems.append(btn)
                continue
            elems.append(sar.obj2html(crt, p.nickname))
        return E.p(*join_elems(elems, sep=", "))




from lino.modlib.checkdata.choicelists import Checker

class GroupChecker(Checker):
    verbose_name = _("Check for missing courses")
    model = Group
    msg_missing = _("No course for {subject} in {group}.")

    def get_checkdata_problems(self, obj, fix=False):
        CertSection = rt.models.cert.CertSection
        tpl = obj.grade.cert_template
        for cs in CertSection.objects.filter(cert_template=tpl):
            if cs.subject_id and cs.subject.advanced:
                qs = Course.objects.filter(group=obj, subject=cs.subject)
                if not qs.exists():
                    yield (True, format_lazy(
                        self.msg_missing, subject=cs.subject, group=obj))
                    if fix:
                        course = Course(subject=cs.subject, group=obj)
                        course.full_clean()
                        course.save()

GroupChecker.activate()



@dd.receiver(dd.post_analyze)
def my_details(sender, **kw):
    sender.models.system.SiteConfigs.set_detail_layout("""
    default_build_method
    simulate_today
    """)


from .ui import *
