import logging
from dataclasses import dataclass
from typing import Optional

from django.db import models
from django.urls import reverse
from imagekit.models import ImageSpecField
from imagekit.processors import ResizeToFit
from scrobbles.dataclasses import BaseLogData, WithPeopleLogData
from scrobbles.mixins import ScrobblableConstants, ScrobblableMixin

logger = logging.getLogger(__name__)
BNULL = {"blank": True, "null": True}


@dataclass
class SpeciesObservationLogData(BaseLogData, WithPeopleLogData):
    observation_id: Optional[int] = None
    photo_urls: Optional[list[str]] = None
    quality_grade: Optional[str] = None
    place_guess: Optional[str] = None
    lat: Optional[float] = None
    lon: Optional[float] = None
    uri: Optional[str] = None
    identifications_count: Optional[int] = None


class SpeciesObservation(ScrobblableMixin):
    scientific_name = models.CharField(max_length=255, **BNULL)
    taxon_id = models.IntegerField(unique=True, db_index=True)
    iconic_taxon_name = models.CharField(max_length=255, **BNULL)
    rank = models.CharField(max_length=255, **BNULL)
    wikipedia_url = models.URLField(max_length=1024, **BNULL)
    photo = models.ImageField(upload_to="nature/species/", **BNULL)
    photo_small = ImageSpecField(
        source="photo",
        processors=[ResizeToFit(100, 100)],
        format="JPEG",
        options={"quality": 60},
    )
    photo_medium = ImageSpecField(
        source="photo",
        processors=[ResizeToFit(300, 300)],
        format="JPEG",
        options={"quality": 75},
    )

    def __str__(self):
        if self.scientific_name:
            return f"{self.title} ({self.scientific_name})"
        return self.title or str(self.uuid)

    def get_absolute_url(self):
        return reverse("nature:species_observation_detail", kwargs={"slug": self.uuid})

    @property
    def subtitle(self):
        return self.scientific_name or ""

    @property
    def run_time_seconds(self) -> int:
        return self.base_run_time_seconds or 300

    @property
    def strings(self) -> ScrobblableConstants:
        return ScrobblableConstants(verb="Observing", tags="leaf")

    @property
    def logdata_cls(self):
        return SpeciesObservationLogData

    @property
    def primary_image_url(self) -> str:
        if self.photo:
            return self.photo.url
        return ""

    def fix_metadata(self) -> None:
        pass

    @classmethod
    def find_or_create(
        cls,
        common_name: str,
        scientific_name: str,
        taxon_id: int,
        iconic_taxon_name: str = "",
        rank: str = "",
        wikipedia_url: str = "",
    ) -> "SpeciesObservation":
        species = cls.objects.filter(taxon_id=taxon_id).first()
        if not species:
            species = cls.objects.create(
                title=common_name,
                scientific_name=scientific_name,
                taxon_id=taxon_id,
                iconic_taxon_name=iconic_taxon_name,
                rank=rank,
                wikipedia_url=wikipedia_url or "",
            )
        return species
