"""Models for PI FYAD plugin."""

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

from allianceauth.eveonline.models import EveCharacter

from .constants import (
    EXTRACTOR_STATUS_ACTIVE,
    EXTRACTOR_STATUS_EXPIRED,
    EXTRACTOR_STATUS_IDLE,
    STORAGE_CAPACITIES,
    VISIBILITY_CHOICES,
    VISIBILITY_PRIVATE,
)
from .managers import (
    CharacterPlanetManager,
    PlanetPinManager,
    PlanetTemplateManager,
    StorageContentsManager,
)


class PiFyadGeneral(models.Model):
    """Proxy model for permissions."""

    class Meta:
        managed = False
        default_permissions = ()
        permissions = [
            ("view_pi", "Can view own PI data"),
            ("view_corp_pi", "Can view corporation PI data"),
            ("view_alliance_pi", "Can view alliance PI data"),
            ("manage_templates", "Can create and manage PI templates"),
        ]


class CharacterOwner(models.Model):
    """Links an EVE character to PI tracking."""

    character = models.OneToOneField(
        EveCharacter,
        on_delete=models.CASCADE,
        related_name="pi_fyad_owner",
        primary_key=True,
    )
    last_planet_sync = models.DateTimeField(null=True, blank=True)
    last_customs_sync = models.DateTimeField(null=True, blank=True)
    sync_enabled = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        default_permissions = ()

    def __str__(self):
        return f"PIOwner: {self.character.character_name}"

    @property
    def needs_planet_sync(self) -> bool:
        """Check if planet data needs refresh."""
        from .constants import PLANET_SYNC_INTERVAL

        if not self.last_planet_sync:
            return True
        elapsed = (timezone.now() - self.last_planet_sync).total_seconds()
        return elapsed >= PLANET_SYNC_INTERVAL

    @property
    def needs_customs_sync(self) -> bool:
        """Check if customs office data needs refresh."""
        from .constants import CUSTOMS_SYNC_INTERVAL

        if not self.last_customs_sync:
            return True
        elapsed = (timezone.now() - self.last_customs_sync).total_seconds()
        return elapsed >= CUSTOMS_SYNC_INTERVAL


class CharacterPlanet(models.Model):
    """A planet installation for a character."""

    owner = models.ForeignKey(
        CharacterOwner,
        on_delete=models.CASCADE,
        related_name="planets",
    )
    planet_id = models.IntegerField()
    planet_type_id = models.IntegerField()
    planet_name = models.CharField(max_length=255, blank=True, default="")
    solar_system_id = models.IntegerField()
    solar_system_name = models.CharField(max_length=255, blank=True, default="")
    upgrade_level = models.IntegerField(default=0)
    num_pins = models.IntegerField(default=0)
    last_update = models.DateTimeField(null=True, blank=True)

    objects = CharacterPlanetManager()

    class Meta:
        default_permissions = ()
        unique_together = [("owner", "planet_id")]
        ordering = ["solar_system_name", "planet_name"]

    def __str__(self):
        return f"{self.owner.character.character_name} - {self.planet_name}"

    @property
    def has_critical_alerts(self) -> bool:
        """Check if any pins have expired extractors or full storage."""
        return self.pins.filter(
            models.Q(extractor_expiry__lt=timezone.now())
            | models.Q(storage_fill_pct__gte=95.0)
        ).exists()

    @property
    def extractor_summary(self) -> dict:
        """Return counts of active/idle/expired extractors."""
        now = timezone.now()
        extractors = self.pins.filter(is_extractor=True)
        active = 0
        idle = 0
        expired = 0
        for pin in extractors:
            status = pin.extractor_status
            if status == EXTRACTOR_STATUS_ACTIVE:
                active += 1
            elif status == EXTRACTOR_STATUS_EXPIRED:
                expired += 1
            else:
                idle += 1
        return {"active": active, "idle": idle, "expired": expired}


class PlanetPin(models.Model):
    """A single pin (structure) on a planet."""

    planet = models.ForeignKey(
        CharacterPlanet,
        on_delete=models.CASCADE,
        related_name="pins",
    )
    pin_id = models.BigIntegerField()
    type_id = models.IntegerField()
    type_name = models.CharField(max_length=255, blank=True, default="")
    group_id = models.IntegerField(default=0)
    schematic_id = models.IntegerField(null=True, blank=True)
    latitude = models.FloatField(default=0.0)
    longitude = models.FloatField(default=0.0)

    # Extractor fields
    is_extractor = models.BooleanField(default=False)
    extractor_product_type_id = models.IntegerField(null=True, blank=True)
    extractor_product_name = models.CharField(max_length=255, blank=True, default="")
    extractor_cycle_time = models.IntegerField(null=True, blank=True, help_text="Seconds per cycle")
    extractor_head_count = models.IntegerField(default=0)
    extractor_qty_per_cycle = models.IntegerField(default=0)
    install_time = models.DateTimeField(null=True, blank=True)
    expiry_time = models.DateTimeField(null=True, blank=True)

    # Storage fields
    is_storage = models.BooleanField(default=False)
    storage_capacity_m3 = models.FloatField(default=0.0)
    storage_used_m3 = models.FloatField(default=0.0)
    storage_fill_pct = models.FloatField(default=0.0)

    # Factory fields
    is_factory = models.BooleanField(default=False)
    factory_tier = models.IntegerField(default=0, help_text="0=unknown, 1=basic, 2=advanced, 3=high-tech")
    factory_output_type_id = models.IntegerField(null=True, blank=True)
    factory_output_name = models.CharField(max_length=255, blank=True, default="")

    last_update = models.DateTimeField(null=True, blank=True)

    objects = PlanetPinManager()

    class Meta:
        default_permissions = ()
        unique_together = [("planet", "pin_id")]
        ordering = ["-is_extractor", "-is_factory", "-is_storage"]

    def __str__(self):
        return f"Pin {self.pin_id}: {self.type_name}"

    @property
    def extractor_status(self) -> str:
        """Return extractor status: active, idle, or expired."""
        if not self.is_extractor:
            return EXTRACTOR_STATUS_IDLE
        if not self.expiry_time:
            return EXTRACTOR_STATUS_IDLE
        now = timezone.now()
        if self.install_time and self.expiry_time > now:
            return EXTRACTOR_STATUS_ACTIVE
        if self.expiry_time <= now:
            return EXTRACTOR_STATUS_EXPIRED
        return EXTRACTOR_STATUS_IDLE

    @property
    def time_remaining(self):
        """Return timedelta until extractor expires, or None."""
        if not self.expiry_time:
            return None
        remaining = self.expiry_time - timezone.now()
        if remaining.total_seconds() < 0:
            return None
        return remaining

    @property
    def eve_image_url(self) -> str:
        """Return EVE image server URL for this type."""
        from .constants import EVE_IMAGE_BASE

        return f"{EVE_IMAGE_BASE}/types/{self.type_id}/icon?size=64"

    def update_storage_capacity(self):
        """Set storage capacity from STORAGE_CAPACITIES mapping."""
        self.storage_capacity_m3 = STORAGE_CAPACITIES.get(self.type_id, 0.0)
        if self.storage_capacity_m3 > 0:
            self.storage_fill_pct = (self.storage_used_m3 / self.storage_capacity_m3) * 100.0
        else:
            self.storage_fill_pct = 0.0


class StorageContents(models.Model):
    """Individual item stack in a storage pin."""

    pin = models.ForeignKey(
        PlanetPin,
        on_delete=models.CASCADE,
        related_name="contents",
    )
    type_id = models.IntegerField()
    type_name = models.CharField(max_length=255, blank=True, default="")
    quantity = models.BigIntegerField(default=0)
    volume_per_unit = models.FloatField(default=0.0)
    total_volume = models.FloatField(default=0.0)

    objects = StorageContentsManager()

    class Meta:
        default_permissions = ()
        unique_together = [("pin", "type_id")]
        ordering = ["-total_volume"]

    def __str__(self):
        return f"{self.type_name} x{self.quantity}"

    @property
    def eve_image_url(self) -> str:
        """Return EVE image server URL for this type."""
        from .constants import EVE_IMAGE_BASE

        return f"{EVE_IMAGE_BASE}/types/{self.type_id}/icon?size=32"


class CustomsOffice(models.Model):
    """Customs office (POCO) data for a planet."""

    planet = models.OneToOneField(
        CharacterPlanet,
        on_delete=models.CASCADE,
        related_name="customs_office",
    )
    office_id = models.BigIntegerField()
    owner_id = models.IntegerField(null=True, blank=True)
    tax_rate = models.FloatField(default=0.0)
    reinforcement_exit_start = models.IntegerField(default=0)
    reinforcement_exit_end = models.IntegerField(default=0)
    allow_alliance = models.BooleanField(default=False)
    allow_standings = models.BooleanField(default=False)
    last_update = models.DateTimeField(null=True, blank=True)

    class Meta:
        default_permissions = ()

    def __str__(self):
        return f"POCO {self.office_id} (tax: {self.tax_rate:.1%})"


class PlanetTemplate(models.Model):
    """Saved planet setup template for sharing."""

    name = models.CharField(max_length=255)
    description = models.TextField(blank=True, default="")
    planet_type_id = models.IntegerField(help_text="EVE planet type ID this template targets")
    planet_type_name = models.CharField(max_length=100, blank=True, default="")

    created_by = models.ForeignKey(
        EveCharacter,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="pi_templates_created",
    )
    corporation_id = models.IntegerField(null=True, blank=True)
    alliance_id = models.IntegerField(null=True, blank=True)

    visibility = models.CharField(
        max_length=20,
        choices=VISIBILITY_CHOICES,
        default=VISIBILITY_PRIVATE,
    )

    # Template data — JSON blob of pin layout + routes
    template_data = models.JSONField(
        default=dict,
        help_text="Parsed clipboard data: pins, links, routes",
    )
    clipboard_raw = models.TextField(
        blank=True,
        default="",
        help_text="Raw clipboard text that was parsed to create this template",
    )

    # Metadata
    pin_count = models.IntegerField(default=0)
    factory_count = models.IntegerField(default=0)
    extractor_count = models.IntegerField(default=0)
    output_products = models.JSONField(default=list, help_text="List of final output type names")

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    objects = PlanetTemplateManager()

    class Meta:
        default_permissions = ()
        ordering = ["-updated_at"]

    def __str__(self):
        return f"Template: {self.name} ({self.planet_type_name})"


class TemplatePin(models.Model):
    """A pin definition within a planet template."""

    template = models.ForeignKey(
        PlanetTemplate,
        on_delete=models.CASCADE,
        related_name="template_pins",
    )
    pin_index = models.IntegerField(help_text="Order index within the template")
    type_id = models.IntegerField()
    type_name = models.CharField(max_length=255, blank=True, default="")
    group_id = models.IntegerField(default=0)
    latitude = models.FloatField(default=0.0)
    longitude = models.FloatField(default=0.0)
    schematic_id = models.IntegerField(null=True, blank=True)

    is_extractor = models.BooleanField(default=False)
    is_factory = models.BooleanField(default=False)
    is_storage = models.BooleanField(default=False)

    factory_tier = models.IntegerField(default=0)
    factory_output_type_id = models.IntegerField(null=True, blank=True)
    factory_output_name = models.CharField(max_length=255, blank=True, default="")

    class Meta:
        default_permissions = ()
        ordering = ["pin_index"]
        unique_together = [("template", "pin_index")]

    def __str__(self):
        return f"TemplatePin #{self.pin_index}: {self.type_name}"
