"""Administrative audit-log model.

An append-only record of every important action a Super Admin performs
(granting premium, moderating listings, managing advertisements…). Rows are only
ever inserted — never updated or deleted through the application — so the table
is a tamper-evident trail for accountability and traceability.

Privacy: raw IP addresses and user agents are **never** stored — only salted
SHA-256 hashes (``ip_hash`` / ``user_agent_hash``), reusing the same hashing
helper as :class:`~app.models.marketplace.ListingView`.
"""

from __future__ import annotations

import json

from app.extensions import db
from app.models.base import BaseModel, BigIntegerType, utcnow


class AdminAuditLog(BaseModel):
    """A single administrative action, captured for the audit trail."""

    __tablename__ = "admin_audit_logs"
    __table_args__ = (
        db.Index("ix_admin_audit_logs_admin_id", "admin_id"),
        db.Index("ix_admin_audit_logs_action", "action"),
        db.Index("ix_admin_audit_logs_entity_type", "entity_type"),
        db.Index("ix_admin_audit_logs_created_at", "created_at"),
    )

    admin_id = db.Column(BigIntegerType, db.ForeignKey("users.id"), nullable=False)
    # Stable action key (e.g. ``premium_granted``); the human label is derived
    # from the service action catalog so new actions need no schema change.
    action = db.Column(db.String(64), nullable=False)
    entity_type = db.Column(db.String(32), nullable=True)
    entity_public_id = db.Column(db.CHAR(36), nullable=True)
    entity_name = db.Column(db.String(255), nullable=True)
    # Structured context, serialised as JSON text (portable across MySQL/SQLite).
    details = db.Column(db.Text, nullable=True)
    ip_hash = db.Column(db.CHAR(64), nullable=True)
    user_agent_hash = db.Column(db.CHAR(64), nullable=True)
    created_at = db.Column(db.DateTime(timezone=True), nullable=False, default=utcnow)

    admin = db.relationship("User", foreign_keys=[admin_id])

    @property
    def details_data(self) -> dict:
        """Parsed ``details`` JSON (empty dict when absent or malformed)."""
        if not self.details:
            return {}
        try:
            value = json.loads(self.details)
        except (ValueError, TypeError):
            return {}
        return value if isinstance(value, dict) else {"value": value}

    def __repr__(self) -> str:
        return f"<AdminAuditLog id={self.id} action={self.action!r} admin_id={self.admin_id}>"
