"""Habitat-related models for lara_django_organisms.

This module contains models related to organism habitats, including
HabitatClass, HabitatParameter, and Habitat.

:authors: mark doerr <mark.doerr@uni-greifswald.de>
"""

import uuid

from django.conf import settings
from django.db import models
from django.utils import timezone

from lara_django_base.models import PhysicalUnit

from .base import ExtraData


class HabitatClass(models.Model):
    """Classes of habitats.

    Examples: maritime, terrestrial, shore, etc.
    """

    model_curi = "lara:organisms/HabitatClass"
    habitatclass_id = models.UUIDField(
        primary_key=True,
        default=uuid.uuid4,
        editable=False,
    )
    name = models.TextField(
        unique=True,
        help_text="maritime, terrestrial, shore",
    )
    iri = models.URLField(
        blank=True,
        null=True,
        unique=True,
        max_length=512,
        help_text="International Resource Identifier - IRI: is used for semantic representation",
    )
    description = models.TextField(
        blank=True,
        help_text="description of the habitat class",
    )

    def save(self, *args, **kwargs):
        """Generate default IRI if not provided."""
        if self.iri is None or self.iri == "":
            self.iri = (
                f"{settings.LARA_PREFIXES['lara']}organisms/HabitatClass/"
                f"{self.name.replace(' ', '_').lower().strip()}"
            )

        super().save(*args, **kwargs)

    def __str__(self):
        """Return the name of the habitat class."""
        return self.name or ""

    def __repr__(self):
        """Return the name of the habitat class."""
        return self.name or ""

    class Meta:
        """Meta options for HabitatClass model."""

        verbose_name_plural = "HabitatClasses"


class HabitatParameter(models.Model):
    """Class level Habitat Parameters.

    Can be used to model all kinds of general habitat parameters
    that are common for all organisms of a certain class.
    Habitat parameters of an individual organism should be captured in the
    organism store.

    Examples of these parameters could be:
    - moisture, pH, nutrients, geological properties
    - geo_width_min, geo_width_max
    - temperature_average, temperature_min, temperature_max
    - oxygen_concentration_min, oxygen_concentration_max, oxygen_concentration_average
    - humidity_average
    - pH_average
    - salt concentration
    - moisture_air_min, moisture_air_max, moisture_air_average
    - light_during_day_min, light_during_day_max, light_during_day_average
    - height_min, height_max

    :TODO: parts should be moved to ontology
    """

    model_curi = "lara:organisms/HabitatParameter"
    habitatparameter_id = models.UUIDField(
        primary_key=True,
        default=uuid.uuid4,
        editable=False,
    )
    name_display = models.TextField(
        help_text="human readable display name of the habitat parameter, can contain spaces"
    )
    name = models.TextField(
        unique=True,
        help_text="name of the habitat parameter, e.g. temperature, moisture, pH, ...",
    )
    iri = models.URLField(
        blank=True,
        null=True,
        unique=True,
        max_length=512,
        help_text="International Resource Identifier - IRI: is used for semantic representation",
    )
    value_range = models.JSONField(
        null=True,
        blank=True,
        help_text="range of values for this parameter, like min, max, average, ...",
    )
    unit = models.ForeignKey(
        PhysicalUnit,
        on_delete=models.CASCADE,
        related_name="%(app_label)s_%(class)s_unit_related",
        related_query_name="%(app_label)s_%(class)s_unit_related_query",
        blank=True,
        null=True,
        help_text="physical unit of the parameter, e.g. K, mol/L, ...",
    )
    data_extra = models.ManyToManyField(
        ExtraData,
        related_name="%(app_label)s_%(class)s_data_extra_related",
        related_query_name="%(app_label)s_%(class)s_data_extra_related_query",
        blank=True,
        help_text="e.g. more information about this particular parameter ...",
    )
    description = models.TextField(
        null=True,
        blank=True,
        help_text="description of the habitat parameter",
    )
    datetime_last_modified = models.DateTimeField(
        blank=True,
        null=True,
        help_text="date and time when habitat parameter data was last modified",
    )

    def save(self, *args, **kwargs):
        """Generate default values for name and IRI."""
        if self.name is None or self.name == "":
            self.name = self.name_display.replace(" ", "_").lower().strip()

        if self.iri is None or self.iri == "":
            self.iri = (
                f"{settings.LARA_PREFIXES['lara']}organisms/HabitatParameter/"
                f"{self.name.replace(' ', '_').lower().strip()}"
            )

        self.datetime_last_modified = timezone.now()

        super().save(*args, **kwargs)

    def __str__(self):
        """Return the name of the habitat parameter."""
        return self.name or ""

    def __repr__(self):
        """Return the name of the habitat parameter."""
        return self.name or ""


class Habitat(models.Model):
    """Information about the living conditions of an organism.

    Examples: temperature, moisture, pH, etc.
    """

    model_curi = "lara:organisms/Habitat"
    habitat_id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    name_display = models.TextField(
        help_text="human readable display name of the habitat, can contain spaces"
    )
    name = models.TextField(
        blank=True,
        null=True,
        help_text="habitat name with namespaces, like sea.shore, sea.deepsee, land.vulcan",
    )
    iri = models.URLField(
        blank=True,
        null=True,
        unique=True,
        max_length=512,
        help_text="International Resource Identifier - IRI: is used for semantic representation",
    )
    habitat_class = models.ForeignKey(
        HabitatClass,
        on_delete=models.CASCADE,
        related_name="%(app_label)s_%(class)s_habitat_class_related",
        related_query_name="%(app_label)s_%(class)s_habitat_class_related_query",
        blank=True,
        null=True,
        help_text="class of the habitat, like maritime, terrestrial, shore, ...",
    )
    parameters = models.ManyToManyField(
        HabitatParameter,
        blank=True,
        related_name="%(app_label)s_%(class)s_parameters_related",
        related_query_name="%(app_label)s_%(class)s_parameters_related_query",
        help_text="e.g. more parameters, like nutrients, ...",
    )
    description = models.TextField(
        null=True,
        blank=True,
        help_text="description of the habitat",
    )
    datetime_last_modified = models.DateTimeField(
        blank=True,
        null=True,
        help_text="date and time when habitat data was last modified",
    )

    def save(self, *args, **kwargs):
        """Generate default IRI if not provided."""
        if self.iri is None or self.iri == "":
            self.iri = (
                f"{settings.LARA_PREFIXES['lara']}organisms/habitat/"
                f"{self.name.replace(' ', '_').lower().strip()}"
            )

        self.datetime_last_modified = timezone.now()

        super().save(*args, **kwargs)

    def __str__(self):
        """Return the name of the habitat."""
        return self.name or ""

    def __repr__(self):
        """Return the name of the habitat."""
        return self.name or ""
