import hashlib
import uuid

import pghistory
from django.conf import settings
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.db import models
from django.utils.text import slugify

from apps.core.history import TrackedModel


@pghistory.track()
class SlugHistory(models.Model):
    """
    Model for tracking slug changes across all models that use slugs.
    Uses generic relations to work with any model.
    """

    content_type = models.ForeignKey(
        ContentType,
        on_delete=models.CASCADE,
        help_text="Type of model this slug belongs to",
    )
    object_id = models.CharField(
        max_length=50,
        help_text="ID of the object this slug belongs to",
    )  # Using CharField to work with our custom IDs
    content_object = GenericForeignKey("content_type", "object_id")

    old_slug = models.SlugField(max_length=200, help_text="Previous slug value")
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name = "Slug History"
        verbose_name_plural = "Slug Histories"
        indexes = [
            models.Index(fields=["content_type", "object_id"]),
            models.Index(fields=["old_slug"]),
        ]
        ordering = ["-created_at"]

    def __str__(self):
        return f"Old slug '{self.old_slug}' for {self.content_object}"


class SluggedModel(TrackedModel):
    """
    Abstract base model that provides slug functionality with history tracking.
    """

    name = models.CharField(max_length=200, help_text="Name of the object")
    slug = models.SlugField(max_length=200, unique=True, help_text="URL-friendly identifier")

    class Meta(TrackedModel.Meta):
        abstract = True

    def save(self, *args, **kwargs):
        # Get the current instance from DB if it exists
        if self.pk:
            try:
                old_instance = self.__class__.objects.get(pk=self.pk)
                # If slug has changed, save the old one to history
                if old_instance.slug != self.slug:
                    SlugHistory.objects.create(
                        content_type=ContentType.objects.get_for_model(self),
                        object_id=getattr(self, self.get_id_field_name()),
                        old_slug=old_instance.slug,
                    )
            except self.__class__.DoesNotExist:
                pass

        # Generate slug if not set
        if not self.slug:
            self.slug = slugify(self.name)

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

    def get_id_field_name(self):
        """
        Returns the name of the read-only ID field for this model.
        Should be overridden by subclasses.
        """
        raise NotImplementedError("Subclasses of SluggedModel must implement get_id_field_name()")

    @classmethod
    def get_by_slug(cls, slug):
        """
        Get an object by its current or historical slug.
        Returns (object, is_old_slug) tuple.
        """
        try:
            # Try to get by current slug first
            return cls.objects.get(slug=slug), False
        except cls.DoesNotExist:
            # Check pghistory first if available
            try:
                import pghistory.models

                history_entries = pghistory.models.Events.objects.filter(
                    pgh_model=f"{cls._meta.app_label}.{cls._meta.model_name}", slug=slug
                ).order_by("-pgh_created_at")

                if history_entries:
                    history_entry = history_entries.first()
                    if history_entry:
                        return cls.objects.get(id=history_entry.pgh_obj_id), True
            except (ImportError, AttributeError):
                pass

            # Try to find in manual slug history as fallback
            history = (
                SlugHistory.objects.filter(
                    content_type=ContentType.objects.get_for_model(cls),
                    old_slug=slug,
                )
                .order_by("-created_at")
                .first()
            )

            if history:
                return (
                    cls.objects.get(**{cls().get_id_field_name(): history.object_id}),
                    True,
                )

            raise cls.DoesNotExist(f"{cls.__name__} with slug '{slug}' does not exist") from None


class ApplicationError(models.Model):
    """
    Stores application errors from frontend and backend sources.

    Errors are captured automatically via middleware (backend) or
    reported via API (frontend) and displayed in the admin dashboard.
    """

    class Severity(models.TextChoices):
        CRITICAL = "critical", "Critical"
        HIGH = "high", "High"
        MEDIUM = "medium", "Medium"
        LOW = "low", "Low"

    class Source(models.TextChoices):
        FRONTEND = "frontend", "Frontend"
        BACKEND = "backend", "Backend"
        API = "api", "API"

    # Identity
    error_id = models.UUIDField(
        unique=True,
        default=uuid.uuid4,
        db_index=True,
        help_text="Unique identifier for this error instance",
    )
    request_id = models.CharField(
        max_length=255,
        blank=True,
        db_index=True,
        help_text="Request correlation ID if available",
    )

    # Error information
    error_type = models.CharField(
        max_length=100,
        db_index=True,
        help_text="Type/class of the error (e.g., 'ValidationError', 'TypeError')",
    )
    error_message = models.TextField(
        help_text="Human-readable error message",
    )
    error_stack = models.TextField(
        blank=True,
        help_text="Stack trace if available",
    )
    error_code = models.CharField(
        max_length=50,
        blank=True,
        db_index=True,
        help_text="Application-specific error code",
    )
    severity = models.CharField(
        max_length=20,
        choices=Severity.choices,
        default=Severity.MEDIUM,
        db_index=True,
        help_text="Error severity level",
    )
    source = models.CharField(
        max_length=20,
        choices=Source.choices,
        db_index=True,
        help_text="Where the error originated",
    )

    # Request context
    endpoint = models.CharField(
        max_length=500,
        blank=True,
        help_text="URL/endpoint where the error occurred",
    )
    http_method = models.CharField(
        max_length=10,
        blank=True,
        help_text="HTTP method of the request",
    )
    http_status = models.PositiveIntegerField(
        null=True,
        blank=True,
        help_text="HTTP status code returned",
    )
    user_agent = models.TextField(
        blank=True,
        help_text="User agent string from the client",
    )

    # User context
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="application_errors",
        help_text="User who encountered the error",
    )
    ip_address_hash = models.CharField(
        max_length=64,
        blank=True,
        db_index=True,
        help_text="Hashed IP address for rate limiting (privacy-preserving)",
    )

    # Extended metadata
    metadata = models.JSONField(
        default=dict,
        blank=True,
        help_text="Additional context (action, entity info, etc.)",
    )
    environment = models.JSONField(
        default=dict,
        blank=True,
        help_text="Client environment info (viewport, browser, etc.)",
    )

    # Timestamps and resolution
    created_at = models.DateTimeField(
        auto_now_add=True,
        db_index=True,
        help_text="When the error was recorded",
    )
    resolved = models.BooleanField(
        default=False,
        db_index=True,
        help_text="Whether this error has been addressed",
    )
    resolved_at = models.DateTimeField(
        null=True,
        blank=True,
        help_text="When the error was marked resolved",
    )
    resolved_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="resolved_errors",
        help_text="Admin who resolved this error",
    )
    resolution_notes = models.TextField(
        blank=True,
        help_text="Notes about how the error was resolved",
    )

    class Meta:
        ordering = ["-created_at"]
        verbose_name = "Application Error"
        verbose_name_plural = "Application Errors"
        indexes = [
            models.Index(fields=["severity", "created_at"]),
            models.Index(fields=["source", "created_at"]),
            models.Index(fields=["error_type", "created_at"]),
            models.Index(fields=["resolved", "created_at"]),
        ]

    def __str__(self) -> str:
        return f"[{self.severity.upper()}] {self.error_type}: {self.error_message[:50]}"

    @staticmethod
    def hash_ip(ip_address: str) -> str:
        """Hash an IP address for privacy-preserving storage."""
        if not ip_address:
            return ""
        salt = getattr(settings, "SECRET_KEY", "")[:16]
        return hashlib.sha256(f"{salt}{ip_address}".encode()).hexdigest()

    @property
    def short_error_id(self) -> str:
        """Return first 8 characters of error_id for display."""
        return str(self.error_id)[:8]


class SystemAlert(models.Model):
    """
    System-level alerts for monitoring application health.

    Alert types include orphaned images, stale submissions, circular dependencies,
    validation errors, ban attempts, upload timeouts, and high error rates.
    """

    class AlertType(models.TextChoices):
        ORPHANED_IMAGES = "orphaned_images", "Orphaned Images"
        STALE_SUBMISSIONS = "stale_submissions", "Stale Submissions"
        CIRCULAR_DEPENDENCY = "circular_dependency", "Circular Dependency"
        VALIDATION_ERROR = "validation_error", "Validation Error"
        BAN_ATTEMPT = "ban_attempt", "Ban Attempt"
        UPLOAD_TIMEOUT = "upload_timeout", "Upload Timeout"
        HIGH_ERROR_RATE = "high_error_rate", "High Error Rate"
        DATABASE_CONNECTION = "database_connection", "Database Connection"
        MEMORY_USAGE = "memory_usage", "Memory Usage"
        QUEUE_BACKUP = "queue_backup", "Queue Backup"

    class Severity(models.TextChoices):
        LOW = "low", "Low"
        MEDIUM = "medium", "Medium"
        HIGH = "high", "High"
        CRITICAL = "critical", "Critical"

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    alert_type = models.CharField(
        max_length=50,
        choices=AlertType.choices,
        db_index=True,
        help_text="Type of system alert",
    )
    severity = models.CharField(
        max_length=20,
        choices=Severity.choices,
        db_index=True,
        help_text="Alert severity level",
    )
    message = models.TextField(help_text="Human-readable alert message")
    metadata = models.JSONField(
        null=True,
        blank=True,
        help_text="Additional context data for this alert",
    )
    resolved_at = models.DateTimeField(
        null=True,
        blank=True,
        db_index=True,
        help_text="When this alert was resolved",
    )
    resolved_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="resolved_system_alerts",
        help_text="Admin who resolved this alert",
    )
    created_at = models.DateTimeField(auto_now_add=True, db_index=True)

    class Meta:
        ordering = ["-created_at"]
        verbose_name = "System Alert"
        verbose_name_plural = "System Alerts"
        indexes = [
            models.Index(fields=["severity", "created_at"]),
            models.Index(fields=["alert_type", "created_at"]),
            models.Index(fields=["resolved_at", "created_at"]),
        ]

    def __str__(self) -> str:
        return f"[{self.get_severity_display()}] {self.get_alert_type_display()}: {self.message[:50]}"

    @property
    def is_resolved(self) -> bool:
        return self.resolved_at is not None


class RateLimitAlertConfig(models.Model):
    """
    Configuration for rate limit alert thresholds.

    Defines thresholds that trigger alerts when exceeded.
    """

    class MetricType(models.TextChoices):
        BLOCK_RATE = "block_rate", "Block Rate"
        TOTAL_REQUESTS = "total_requests", "Total Requests"
        UNIQUE_IPS = "unique_ips", "Unique IPs"
        FUNCTION_SPECIFIC = "function_specific", "Function Specific"

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    metric_type = models.CharField(
        max_length=50,
        choices=MetricType.choices,
        db_index=True,
        help_text="Type of metric to monitor",
    )
    threshold_value = models.FloatField(help_text="Threshold value that triggers alert")
    time_window_ms = models.IntegerField(help_text="Time window in milliseconds for measurement")
    function_name = models.CharField(
        max_length=100,
        null=True,
        blank=True,
        help_text="Specific function to monitor (for function_specific metric type)",
    )
    enabled = models.BooleanField(default=True, db_index=True, help_text="Whether this config is active")
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ["metric_type", "-created_at"]
        verbose_name = "Rate Limit Alert Config"
        verbose_name_plural = "Rate Limit Alert Configs"

    def __str__(self) -> str:
        return f"{self.get_metric_type_display()}: threshold={self.threshold_value}"


class RateLimitAlert(models.Model):
    """
    Alerts triggered when rate limit thresholds are exceeded.
    """

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    config = models.ForeignKey(
        RateLimitAlertConfig,
        on_delete=models.CASCADE,
        related_name="alerts",
        help_text="Configuration that triggered this alert",
    )
    metric_type = models.CharField(max_length=50, help_text="Type of metric")
    metric_value = models.FloatField(help_text="Actual value that triggered the alert")
    threshold_value = models.FloatField(help_text="Threshold that was exceeded")
    time_window_ms = models.IntegerField(help_text="Time window of measurement")
    function_name = models.CharField(
        max_length=100,
        null=True,
        blank=True,
        help_text="Function name if applicable",
    )
    alert_message = models.TextField(help_text="Descriptive alert message")
    resolved_at = models.DateTimeField(
        null=True,
        blank=True,
        db_index=True,
        help_text="When this alert was resolved",
    )
    resolved_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        null=True,
        blank=True,
        on_delete=models.SET_NULL,
        related_name="resolved_rate_limit_alerts",
        help_text="Admin who resolved this alert",
    )
    created_at = models.DateTimeField(auto_now_add=True, db_index=True)

    class Meta:
        ordering = ["-created_at"]
        verbose_name = "Rate Limit Alert"
        verbose_name_plural = "Rate Limit Alerts"
        indexes = [
            models.Index(fields=["metric_type", "created_at"]),
            models.Index(fields=["resolved_at", "created_at"]),
        ]

    def __str__(self) -> str:
        return f"{self.metric_type}: {self.metric_value} > {self.threshold_value}"

    @property
    def is_resolved(self) -> bool:
        return self.resolved_at is not None


class Incident(models.Model):
    """
    Groups related alerts for coordinated investigation.
    
    Incidents provide a higher-level view of system issues,
    allowing teams to track and resolve related alerts together.
    """

    class Status(models.TextChoices):
        OPEN = "open", "Open"
        INVESTIGATING = "investigating", "Investigating"
        RESOLVED = "resolved", "Resolved"
        CLOSED = "closed", "Closed"

    class Severity(models.TextChoices):
        LOW = "low", "Low"
        MEDIUM = "medium", "Medium"
        HIGH = "high", "High"
        CRITICAL = "critical", "Critical"

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    incident_number = models.CharField(
        max_length=20,
        unique=True,
        db_index=True,
        help_text="Auto-generated incident number (INC-YYYYMMDD-XXXX)",
    )
    title = models.CharField(max_length=255, help_text="Brief description of the incident")
    description = models.TextField(null=True, blank=True, help_text="Detailed description")
    severity = models.CharField(
        max_length=20,
        choices=Severity.choices,
        db_index=True,
        help_text="Incident severity level",
    )
    status = models.CharField(
        max_length=20,
        choices=Status.choices,
        default=Status.OPEN,
        db_index=True,
        help_text="Current incident status",
    )

    # Timestamps
    detected_at = models.DateTimeField(auto_now_add=True, help_text="When the incident was detected")
    acknowledged_at = models.DateTimeField(null=True, blank=True, help_text="When someone started investigating")
    acknowledged_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="acknowledged_incidents",
        help_text="User who acknowledged the incident",
    )
    resolved_at = models.DateTimeField(null=True, blank=True, help_text="When the incident was resolved")
    resolved_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="resolved_incidents",
        help_text="User who resolved the incident",
    )
    resolution_notes = models.TextField(null=True, blank=True, help_text="Notes about the resolution")

    # Computed field (denormalized for performance)
    alert_count = models.PositiveIntegerField(default=0, help_text="Number of linked alerts")

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

    class Meta:
        ordering = ["-detected_at"]
        verbose_name = "Incident"
        verbose_name_plural = "Incidents"
        indexes = [
            models.Index(fields=["status", "detected_at"]),
            models.Index(fields=["severity", "detected_at"]),
        ]

    def __str__(self) -> str:
        return f"{self.incident_number}: {self.title}"

    def save(self, *args, **kwargs):
        if not self.incident_number:
            # Auto-generate incident number: INC-YYYYMMDD-XXXX
            from django.utils import timezone

            today = timezone.now().strftime("%Y%m%d")
            count = Incident.objects.filter(incident_number__startswith=f"INC-{today}").count() + 1
            self.incident_number = f"INC-{today}-{count:04d}"
        super().save(*args, **kwargs)

    def update_alert_count(self):
        """Update the denormalized alert_count field."""
        self.alert_count = self.linked_alerts.count()
        self.save(update_fields=["alert_count"])


class IncidentAlert(models.Model):
    """
    Links alerts to incidents (many-to-many through table).
    
    Supports linking both system alerts and rate limit alerts.
    """

    class AlertSource(models.TextChoices):
        SYSTEM = "system", "System Alert"
        RATE_LIMIT = "rate_limit", "Rate Limit Alert"

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    incident = models.ForeignKey(
        Incident,
        on_delete=models.CASCADE,
        related_name="linked_alerts",
        help_text="The incident this alert is linked to",
    )
    alert_source = models.CharField(
        max_length=20,
        choices=AlertSource.choices,
        help_text="Source type of the alert",
    )
    alert_id = models.UUIDField(help_text="ID of the linked alert")
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name = "Incident Alert"
        verbose_name_plural = "Incident Alerts"
        unique_together = ["incident", "alert_source", "alert_id"]
        indexes = [
            models.Index(fields=["alert_source", "alert_id"]),
        ]

    def __str__(self) -> str:
        return f"{self.incident.incident_number} <- {self.alert_source}:{self.alert_id}"

    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)
        # Update the incident's alert count
        self.incident.update_alert_count()

    def delete(self, *args, **kwargs):
        incident = self.incident
        super().delete(*args, **kwargs)
        # Update the incident's alert count
        incident.update_alert_count()


class RequestMetadata(models.Model):
    """
    Comprehensive request tracking for monitoring and debugging.

    Stores detailed information about API requests, including timing,
    errors, user context, and resolution status. Used by the admin
    dashboard for error monitoring and analytics.
    """

    class Severity(models.TextChoices):
        DEBUG = "debug", "Debug"
        INFO = "info", "Info"
        WARNING = "warning", "Warning"
        ERROR = "error", "Error"
        CRITICAL = "critical", "Critical"

    # Identity & Correlation
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    request_id = models.CharField(
        max_length=255,
        unique=True,
        db_index=True,
        help_text="Unique request identifier for correlation",
    )
    trace_id = models.CharField(
        max_length=255,
        blank=True,
        null=True,
        db_index=True,
        help_text="Distributed tracing ID",
    )
    session_id = models.CharField(
        max_length=255,
        blank=True,
        null=True,
        db_index=True,
        help_text="User session identifier",
    )
    parent_request_id = models.CharField(
        max_length=255,
        blank=True,
        null=True,
        help_text="Parent request ID for nested requests",
    )

    # Request Information
    action = models.CharField(
        max_length=255,
        blank=True,
        null=True,
        help_text="Action/operation being performed",
    )
    method = models.CharField(
        max_length=10,
        blank=True,
        null=True,
        help_text="HTTP method (GET, POST, etc.)",
    )
    endpoint = models.CharField(
        max_length=500,
        blank=True,
        null=True,
        db_index=True,
        help_text="API endpoint or URL path",
    )
    request_method = models.CharField(
        max_length=10,
        blank=True,
        null=True,
        help_text="HTTP request method",
    )
    request_path = models.CharField(
        max_length=500,
        blank=True,
        null=True,
        help_text="Request URL path",
    )
    affected_route = models.CharField(
        max_length=255,
        blank=True,
        null=True,
        help_text="Frontend route affected",
    )

    # Response Information
    http_status = models.PositiveIntegerField(
        blank=True,
        null=True,
        db_index=True,
        help_text="HTTP status code",
    )
    status_code = models.PositiveIntegerField(
        blank=True,
        null=True,
        help_text="Status code (alias for http_status)",
    )
    response_status = models.PositiveIntegerField(
        blank=True,
        null=True,
        help_text="Response status code",
    )
    success = models.BooleanField(
        blank=True,
        null=True,
        db_index=True,
        help_text="Whether the request was successful",
    )

    # Timing
    started_at = models.DateTimeField(
        auto_now_add=True,
        help_text="When the request started",
    )
    completed_at = models.DateTimeField(
        blank=True,
        null=True,
        help_text="When the request completed",
    )
    duration_ms = models.PositiveIntegerField(
        blank=True,
        null=True,
        help_text="Request duration in milliseconds",
    )
    response_time_ms = models.PositiveIntegerField(
        blank=True,
        null=True,
        help_text="Response time in milliseconds",
    )

    # Error Information
    error_type = models.CharField(
        max_length=100,
        blank=True,
        null=True,
        db_index=True,
        help_text="Type/class of error",
    )
    error_message = models.TextField(
        blank=True,
        null=True,
        help_text="Error message",
    )
    error_stack = models.TextField(
        blank=True,
        null=True,
        help_text="Error stack trace",
    )
    error_code = models.CharField(
        max_length=50,
        blank=True,
        null=True,
        db_index=True,
        help_text="Application error code",
    )
    error_origin = models.CharField(
        max_length=100,
        blank=True,
        null=True,
        help_text="Where the error originated",
    )
    component_stack = models.TextField(
        blank=True,
        null=True,
        help_text="React component stack trace",
    )
    severity = models.CharField(
        max_length=20,
        choices=Severity.choices,
        default=Severity.INFO,
        db_index=True,
        help_text="Error severity level",
    )

    # Resolution
    is_resolved = models.BooleanField(
        default=False,
        db_index=True,
        help_text="Whether this error has been resolved",
    )
    resolved_at = models.DateTimeField(
        blank=True,
        null=True,
        help_text="When the error was resolved",
    )
    resolved_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        blank=True,
        null=True,
        on_delete=models.SET_NULL,
        related_name="resolved_request_metadata",
        help_text="User who resolved this error",
    )
    resolution_notes = models.TextField(
        blank=True,
        null=True,
        help_text="Notes about resolution",
    )

    # Retry Information
    retry_count = models.PositiveIntegerField(
        default=0,
        help_text="Number of retry attempts",
    )
    retry_attempts = models.PositiveIntegerField(
        blank=True,
        null=True,
        help_text="Total retry attempts made",
    )

    # User Context
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        blank=True,
        null=True,
        on_delete=models.SET_NULL,
        related_name="request_metadata",
        help_text="User who made the request",
    )
    user_agent = models.TextField(
        blank=True,
        null=True,
        help_text="User agent string",
    )
    ip_address_hash = models.CharField(
        max_length=64,
        blank=True,
        null=True,
        db_index=True,
        help_text="Hashed IP address",
    )
    client_version = models.CharField(
        max_length=50,
        blank=True,
        null=True,
        help_text="Client application version",
    )
    timezone = models.CharField(
        max_length=50,
        blank=True,
        null=True,
        help_text="User timezone",
    )
    referrer = models.TextField(
        blank=True,
        null=True,
        help_text="HTTP referrer",
    )

    # Entity Context
    entity_type = models.CharField(
        max_length=50,
        blank=True,
        null=True,
        db_index=True,
        help_text="Type of entity affected",
    )
    entity_id = models.CharField(
        max_length=255,
        blank=True,
        null=True,
        db_index=True,
        help_text="ID of entity affected",
    )

    # Timestamps
    created_at = models.DateTimeField(
        auto_now_add=True,
        db_index=True,
        help_text="When this record was created",
    )

    class Meta:
        ordering = ["-created_at"]
        verbose_name = "Request Metadata"
        verbose_name_plural = "Request Metadata"
        indexes = [
            models.Index(fields=["error_type", "created_at"]),
            models.Index(fields=["severity", "created_at"]),
            models.Index(fields=["is_resolved", "created_at"]),
            models.Index(fields=["user", "created_at"]),
        ]

    def __str__(self) -> str:
        return f"{self.request_id} - {self.endpoint or 'unknown'}"


class RequestBreadcrumb(models.Model):
    """
    Breadcrumb trail for request tracing.

    Stores individual breadcrumb events that occurred during a request,
    useful for debugging and understanding request flow.
    """

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    request_metadata = models.ForeignKey(
        RequestMetadata,
        on_delete=models.CASCADE,
        related_name="request_breadcrumbs",
        help_text="Parent request",
    )
    timestamp = models.DateTimeField(
        help_text="When this breadcrumb occurred",
    )
    category = models.CharField(
        max_length=100,
        help_text="Breadcrumb category (e.g., 'http', 'navigation', 'console')",
    )
    message = models.TextField(
        help_text="Breadcrumb message",
    )
    level = models.CharField(
        max_length=20,
        blank=True,
        null=True,
        help_text="Log level (debug, info, warning, error)",
    )
    sequence_order = models.PositiveIntegerField(
        default=0,
        help_text="Order within the request",
    )

    class Meta:
        ordering = ["sequence_order", "timestamp"]
        verbose_name = "Request Breadcrumb"
        verbose_name_plural = "Request Breadcrumbs"
        indexes = [
            models.Index(fields=["request_metadata", "sequence_order"]),
        ]

    def __str__(self) -> str:
        return f"[{self.category}] {self.message[:50]}"


class ApprovalTransactionMetric(models.Model):
    """
    Metrics for content approval transactions.

    Tracks performance and success/failure of moderation approval
    operations for analytics and debugging.
    """

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)

    # References
    submission_id = models.CharField(
        max_length=255,
        db_index=True,
        help_text="ID of the content submission",
    )
    moderator_id = models.CharField(
        max_length=255,
        db_index=True,
        help_text="ID of the moderator who processed the submission",
    )
    submitter_id = models.CharField(
        max_length=255,
        db_index=True,
        help_text="ID of the user who submitted the content",
    )
    request_id = models.CharField(
        max_length=255,
        blank=True,
        null=True,
        db_index=True,
        help_text="Correlation request ID",
    )

    # Metrics
    success = models.BooleanField(
        db_index=True,
        help_text="Whether the approval was successful",
    )
    duration_ms = models.PositiveIntegerField(
        blank=True,
        null=True,
        help_text="Processing duration in milliseconds",
    )
    items_count = models.PositiveIntegerField(
        default=1,
        help_text="Number of items processed",
    )
    rollback_triggered = models.BooleanField(
        default=False,
        help_text="Whether a rollback was triggered",
    )

    # Error Information
    error_code = models.CharField(
        max_length=50,
        blank=True,
        null=True,
        help_text="Error code if failed",
    )
    error_message = models.TextField(
        blank=True,
        null=True,
        help_text="Error message if failed",
    )
    error_details = models.TextField(
        blank=True,
        null=True,
        help_text="Detailed error information",
    )

    # Timestamps
    created_at = models.DateTimeField(
        auto_now_add=True,
        db_index=True,
        help_text="When this metric was recorded",
    )

    class Meta:
        ordering = ["-created_at"]
        verbose_name = "Approval Transaction Metric"
        verbose_name_plural = "Approval Transaction Metrics"
        indexes = [
            models.Index(fields=["success", "created_at"]),
            models.Index(fields=["moderator_id", "created_at"]),
        ]

    def __str__(self) -> str:
        status = "✓" if self.success else "✗"
        return f"{status} Submission {self.submission_id[:8]} by {self.moderator_id[:8]}"


@pghistory.track()
class Milestone(TrackedModel):
    """
    Timeline event / milestone for any entity.

    Supports various event types like openings, closures, name changes,
    operator changes, and other significant events. Uses a generic
    entity reference pattern to work with Parks, Rides, Companies, etc.

    Maps to frontend milestoneValidationSchema in entityValidationSchemas.ts
    """

    class DatePrecision(models.TextChoices):
        EXACT = "exact", "Exact Date"
        MONTH = "month", "Month and Year"
        YEAR = "year", "Year Only"
        DECADE = "decade", "Decade"
        CENTURY = "century", "Century"
        APPROXIMATE = "approximate", "Approximate"

    # Core event information
    title = models.CharField(
        max_length=200,
        help_text="Title or name of the event",
    )
    description = models.TextField(
        blank=True,
        help_text="Detailed description of the event",
    )
    event_type = models.CharField(
        max_length=50,
        db_index=True,
        help_text="Type of event (e.g., 'opening', 'closing', 'name_change', 'status_change')",
    )
    event_date = models.DateField(
        db_index=True,
        help_text="Date when the event occurred or will occur",
    )
    event_date_precision = models.CharField(
        max_length=20,
        choices=DatePrecision.choices,
        default=DatePrecision.EXACT,
        help_text="Precision of the event date",
    )

    # Generic entity reference
    entity_type = models.CharField(
        max_length=50,
        db_index=True,
        help_text="Type of entity (e.g., 'park', 'ride', 'company')",
    )
    entity_id = models.UUIDField(
        db_index=True,
        help_text="UUID of the associated entity",
    )

    # Display settings
    is_public = models.BooleanField(
        default=True,
        help_text="Whether this milestone is publicly visible",
    )
    display_order = models.IntegerField(
        default=0,
        help_text="Order for displaying multiple milestones on the same date",
    )

    # Change tracking fields (for name_change, operator_change, etc.)
    from_value = models.CharField(
        max_length=200,
        blank=True,
        help_text="Previous value (for change events)",
    )
    to_value = models.CharField(
        max_length=200,
        blank=True,
        help_text="New value (for change events)",
    )
    from_entity_id = models.UUIDField(
        null=True,
        blank=True,
        help_text="Previous entity reference (e.g., old operator)",
    )
    to_entity_id = models.UUIDField(
        null=True,
        blank=True,
        help_text="New entity reference (e.g., new operator)",
    )
    from_location_id = models.UUIDField(
        null=True,
        blank=True,
        help_text="Previous location reference (for relocations)",
    )
    to_location_id = models.UUIDField(
        null=True,
        blank=True,
        help_text="New location reference (for relocations)",
    )

    class Meta(TrackedModel.Meta):
        ordering = ["-event_date", "display_order"]
        verbose_name = "Milestone"
        verbose_name_plural = "Milestones"
        indexes = [
            models.Index(fields=["entity_type", "entity_id"]),
            models.Index(fields=["event_type", "event_date"]),
            models.Index(fields=["is_public", "event_date"]),
        ]

    def __str__(self) -> str:
        return f"{self.title} ({self.event_date})"

