from django.db import models


class KonovaCode(models.Model):
    """
    Representation of the OSIRIS Codelisten codes.

    KonovaCodes will be updated using a command regularly to provide all codes, which are provided by the
    Codelisten application itself. To reduce traffic, we store them in our own database.
    """
    id = models.IntegerField(
        primary_key=True,
        help_text="Regular Id"
    )
    atom_id = models.IntegerField(
        help_text="AtomId; Identifies this code uniquely over all NatIT projects; Duplicates possible",
        null=True,
        blank=True,
    )
    parent = models.ForeignKey(
        "KonovaCode",
        on_delete=models.CASCADE,
        null=True,
        blank=True,
    )
    short_name = models.CharField(
        max_length=500,
        blank=True,
        help_text="Short version of long name",
    )
    long_name = models.CharField(
        max_length=1000,
        blank=True,
        help_text="",
    )
    is_selectable = models.BooleanField(
        default=False,
        help_text="Whether this code shall be used for any select actions or not"
    )
    is_leaf = models.BooleanField(
        default=False,
        help_text="Whether this code has children or not"
    )
    is_archived = models.BooleanField(
        default=False,
        help_text="Whether this code is archived or not"
    )

    def __str__(self, with_parent: bool = True):
        ret_val = ""

        long_name = self.long_name
        short_name = self.short_name

        both_names_exist = long_name is not None and short_name is not None

        if both_names_exist:
            if with_parent and self.parent:
                parent_short_name_exists = self.parent.short_name is not None
                parent_long_name_exists = self.parent.long_name is not None
                if parent_long_name_exists:
                    ret_val += self.parent.long_name + " > "
                elif parent_short_name_exists:
                    ret_val += self.parent.short_name + " > "

            ret_val += long_name

            if short_name and short_name != long_name:
                ret_val += f" ({short_name})"
        else:
            ret_val += str(long_name or short_name)

        return ret_val

    @property
    def str_as_office(self):
        ret_val = self.long_name
        if self.parent:
            ret_val += ", " + self.parent.long_name
        return ret_val

    def add_children(self, order_by: str = "long_name"):
        """ Adds all children (resurcively until leaf) as .children to the KonovaCode

        Returns:
            code (KonovaCode): The manipulated KonovaCode instance
        """
        if self.is_leaf:
            return self

        children = KonovaCode.objects.filter(
            parent=self,
            is_archived=False,
        ).order_by(
            order_by
        )
        self.children = children
        for child in children:
            child.add_children(order_by)
        return self


class KonovaCodeList(models.Model):
    """
    The codelist itself
    """
    id = models.IntegerField(
        primary_key=True,
        help_text="List identifier",
    )
    codes = models.ManyToManyField(
        KonovaCode,
        blank=True,
        help_text="Codes for this list",
        related_name="code_lists"
    )

    def __str__(self):
        return str(self.id)
