from decimal import Decimal
from django.conf import settings
from django.db import models

from apps.core.models import BaseModel


class TelemetryEvent(BaseModel):
    class Domain(models.TextChoices):
        COMMERCE = 'COMMERCE', 'Commerce'
        NETWORK = 'NETWORK', 'Network'
        OPERATIONAL = 'OPERATIONAL', 'Operational'

    event_type = models.CharField(max_length=64, db_index=True)
    event_domain = models.CharField(max_length=16, choices=Domain.choices, db_index=True)
    occurred_at = models.DateTimeField(db_index=True)
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name='telemetry_events',
    )
    session_id = models.CharField(max_length=128, blank=True, default='', db_index=True)
    device = models.CharField(max_length=64, blank=True, default='')
    page = models.CharField(max_length=255, blank=True, default='')
    source = models.CharField(max_length=32, default='frontend')
    metadata = models.JSONField(default=dict, blank=True)
    client_event_id = models.CharField(max_length=128, blank=True, default='', db_index=True)
    retention_expires_at = models.DateTimeField(null=True, blank=True, db_index=True)

    class Meta:
        indexes = [
            models.Index(fields=['event_type', 'occurred_at']),
            models.Index(fields=['event_domain', 'occurred_at']),
            models.Index(fields=['user', 'occurred_at']),
            models.Index(fields=['session_id', 'occurred_at']),
        ]

    def __str__(self):
        return f'{self.event_type} ({self.event_domain}) @ {self.occurred_at}'


class TelemetryKPIAggregate(BaseModel):
    class PeriodType(models.TextChoices):
        DAY = 'DAY', 'Daily'
        WEEK = 'WEEK', 'Weekly'
        MONTH = 'MONTH', 'Monthly'

    period_type = models.CharField(max_length=8, choices=PeriodType.choices, db_index=True)
    period_start = models.DateField(db_index=True)
    period_end = models.DateField(db_index=True)
    event_domain = models.CharField(max_length=16, choices=TelemetryEvent.Domain.choices, db_index=True)
    metrics = models.JSONField(default=dict, blank=True)

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=['period_type', 'period_start', 'event_domain'],
                name='uniq_telemetry_kpi_period_domain',
            )
        ]


class TelemetryCohortSnapshot(BaseModel):
    snapshot_date = models.DateField(db_index=True)
    cohort_name = models.CharField(max_length=64, db_index=True)
    users_count = models.PositiveIntegerField(default=0)
    metrics = models.JSONField(default=dict, blank=True)

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=['snapshot_date', 'cohort_name'],
                name='uniq_telemetry_cohort_snapshot',
            )
        ]


class TelemetryRetentionSnapshot(BaseModel):
    cohort_date = models.DateField(db_index=True)
    retention_day = models.PositiveSmallIntegerField(db_index=True)
    event_domain = models.CharField(
        max_length=16,
        choices=TelemetryEvent.Domain.choices,
        default=TelemetryEvent.Domain.COMMERCE,
        db_index=True,
    )
    cohort_size = models.PositiveIntegerField(default=0)
    active_users = models.PositiveIntegerField(default=0)
    retention_rate = models.DecimalField(max_digits=6, decimal_places=2, default=Decimal('0.00'))

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=['cohort_date', 'retention_day', 'event_domain'],
                name='uniq_telemetry_retention_snapshot',
            )
        ]


class TelemetryFunnelSnapshot(BaseModel):
    snapshot_date = models.DateField(db_index=True)
    funnel_name = models.CharField(max_length=64, db_index=True)
    stage_name = models.CharField(max_length=64, db_index=True)
    stage_order = models.PositiveSmallIntegerField(default=0)
    event_domain = models.CharField(max_length=16, choices=TelemetryEvent.Domain.choices, db_index=True)
    users_count = models.PositiveIntegerField(default=0)
    conversion_rate = models.DecimalField(max_digits=6, decimal_places=2, default=Decimal('0.00'))

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=['snapshot_date', 'funnel_name', 'stage_order', 'event_domain'],
                name='uniq_telemetry_funnel_snapshot',
            )
        ]


class TelemetryAlert(BaseModel):
    class Severity(models.TextChoices):
        INFO = 'INFO', 'Info'
        WARNING = 'WARNING', 'Warning'
        CRITICAL = 'CRITICAL', 'Critical'

    class Status(models.TextChoices):
        OPEN = 'OPEN', 'Open'
        RESOLVED = 'RESOLVED', 'Resolved'

    alert_type = models.CharField(max_length=80, db_index=True)
    severity = models.CharField(max_length=16, choices=Severity.choices, default=Severity.WARNING)
    status = models.CharField(max_length=16, choices=Status.choices, default=Status.OPEN, db_index=True)
    event_domain = models.CharField(
        max_length=16,
        choices=TelemetryEvent.Domain.choices,
        default=TelemetryEvent.Domain.OPERATIONAL,
        db_index=True,
    )
    detected_at = models.DateTimeField(db_index=True)
    resolved_at = models.DateTimeField(null=True, blank=True)
    metric_value = models.DecimalField(max_digits=14, decimal_places=4, default=Decimal('0.0000'))
    threshold_value = models.DecimalField(max_digits=14, decimal_places=4, default=Decimal('0.0000'))
    context = models.JSONField(default=dict, blank=True)

    class Meta:
        indexes = [
            models.Index(fields=['status', 'detected_at']),
            models.Index(fields=['alert_type', 'status']),
        ]
