import secrets
import time

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


def uuid7() -> str:
    """Time-ordered UUID as 32-char hex (matches the project convention)."""
    nanoseconds = time.time_ns()
    uuid_int = (nanoseconds << 16) | secrets.randbits(48)
    return f"{uuid_int:032x}"


def gen_public_key() -> str:
    """Public tracking id embedded in the JS tag. Safe to expose."""
    return f"khub-{secrets.token_hex(8)}"


class Site(models.Model):
    """A website registered for analytics. Each gets a public tracking key."""

    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    name = models.CharField(max_length=120)
    domain = models.CharField(max_length=255, help_text="Primary hostname, e.g. example.com")
    public_key = models.CharField(max_length=32, unique=True, default=gen_public_key, db_index=True)
    is_active = models.BooleanField(default=True)
    # Fetched from the live site at create / refresh time.
    favicon_url = models.URLField(max_length=512, blank=True)
    title = models.CharField(max_length=255, blank=True)
    description = models.TextField(blank=True)
    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True, related_name="analytics_sites"
    )
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = "analytics_sites"
        ordering = ["name"]
        verbose_name = "Analytics Site"
        verbose_name_plural = "Analytics Sites"

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


class Hit(models.Model):
    """A single pageview or custom event sent by a Site's tracking tag."""

    EVENT_PAGEVIEW = "pageview"
    EVENT_CUSTOM = "event"
    EVENT_CHOICES = [(EVENT_PAGEVIEW, "Pageview"), (EVENT_CUSTOM, "Event")]

    site = models.ForeignKey(Site, on_delete=models.CASCADE, related_name="hits", db_index=True)

    event_type = models.CharField(max_length=16, choices=EVENT_CHOICES, default=EVENT_PAGEVIEW, db_index=True)
    event_name = models.CharField(max_length=120, blank=True, db_index=True)

    path = models.CharField(max_length=512, blank=True, db_index=True)
    hostname = models.CharField(max_length=255, blank=True)
    title = models.CharField(max_length=255, blank=True)

    # Hashed identity — never store raw IP. visitor_hash = IP+UA+day for unique counts.
    ip_hash = models.CharField(max_length=64, blank=True, db_index=True)
    visitor_hash = models.CharField(max_length=64, blank=True, db_index=True)
    # Cookieless per-tab session id from the tag (sessionStorage). Groups a visit's pageviews.
    session_id = models.CharField(max_length=64, blank=True, db_index=True)

    country = models.CharField(max_length=64, blank=True, db_index=True)
    country_code = models.CharField(max_length=2, blank=True, db_index=True)

    device = models.CharField(max_length=32, blank=True, db_index=True)  # mobile/tablet/desktop/bot
    os = models.CharField(max_length=64, blank=True)
    browser = models.CharField(max_length=64, blank=True)

    referer = models.CharField(max_length=1024, blank=True)
    referer_host = models.CharField(max_length=255, blank=True, db_index=True)

    utm_source = models.CharField(max_length=128, blank=True, db_index=True)
    utm_medium = models.CharField(max_length=128, blank=True)
    utm_campaign = models.CharField(max_length=128, blank=True, db_index=True)
    utm_term = models.CharField(max_length=128, blank=True)
    utm_content = models.CharField(max_length=128, blank=True)

    props = models.JSONField(default=dict, blank=True)

    created_at = models.DateTimeField(auto_now_add=True, db_index=True)

    class Meta:
        db_table = "analytics_hits"
        ordering = ["-created_at"]
        indexes = [
            models.Index(fields=["site", "created_at"]),
            models.Index(fields=["site", "event_type"]),
            models.Index(fields=["site", "path"]),
            models.Index(fields=["site", "session_id"]),
        ]

    def __str__(self):
        label = self.event_name if self.event_type == self.EVENT_CUSTOM else self.path
        return f"{self.site_id}:{self.event_type}:{label}"


class AccessLog(models.Model):
    """Single request hit against a tracked public resource."""

    RESOURCE_CHOICES = [
        ("shorten_url", "Shorten URL"),
        ("publication", "Publication"),
        ("event", "Event"),
        ("other", "Other"),
    ]

    resource_type = models.CharField(max_length=32, choices=RESOURCE_CHOICES, default="other")
    resource_id = models.CharField(max_length=64, blank=True, db_index=True)
    resource_slug = models.CharField(max_length=255, blank=True, db_index=True)

    path = models.CharField(max_length=512)
    method = models.CharField(max_length=8, default="GET")
    status_code = models.PositiveSmallIntegerField(default=200)
    response_time_ms = models.PositiveIntegerField(default=0)

    # Hashed identity — never store raw IP. Combo of IP+UA used for unique-visitor counts.
    ip_hash = models.CharField(max_length=64, db_index=True)
    visitor_hash = models.CharField(max_length=64, db_index=True)

    country = models.CharField(max_length=64, blank=True, db_index=True)
    country_code = models.CharField(max_length=2, blank=True, db_index=True)

    device = models.CharField(max_length=32, blank=True, db_index=True)  # mobile/tablet/desktop/bot
    os = models.CharField(max_length=64, blank=True)
    browser = models.CharField(max_length=64, blank=True)
    user_agent = models.CharField(max_length=512, blank=True)

    referer = models.CharField(max_length=1024, blank=True)
    referer_host = models.CharField(max_length=255, blank=True, db_index=True)

    tags = models.JSONField(default=list, blank=True)
    utm_source = models.CharField(max_length=128, blank=True, db_index=True)
    utm_medium = models.CharField(max_length=128, blank=True)
    utm_campaign = models.CharField(max_length=128, blank=True, db_index=True)

    created_at = models.DateTimeField(auto_now_add=True, db_index=True)

    class Meta:
        db_table = "analytics_access_logs"
        ordering = ["-created_at"]
        indexes = [
            models.Index(fields=["resource_type", "resource_id"]),
            models.Index(fields=["resource_type", "created_at"]),
        ]

    def __str__(self):
        return f"{self.resource_type}:{self.resource_id or self.resource_slug} {self.path}"
