"""Tenant-aware persistence for the generic QR service."""
from __future__ import annotations

import uuid
from datetime import datetime
from sqlalchemy import JSON, Boolean, CheckConstraint, DateTime, ForeignKey, Index, Integer, String, Text, UniqueConstraint
from sqlalchemy.orm import Mapped, mapped_column
from config.db import Base

def _uuid() -> str: return str(uuid.uuid4())

class QRRecord(Base):
    __tablename__ = "qr_records"
    __table_args__ = (
        Index("ix_qr_token_hash", "public_token_hash", unique=True),
        Index("ix_qr_resource", "tenant_id", "owner_app", "resource_type", "resource_reference"),
        Index("ix_qr_status_expiry", "tenant_id", "status", "expires_at"),
        CheckConstraint("scan_count >= 0 AND successful_use_count >= 0", name="ck_qr_nonnegative_counts"),
    )
    qr_id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid)
    tenant_id: Mapped[str] = mapped_column(String(64), ForeignKey("tenants.tenant_id"), nullable=False, index=True)
    display_name: Mapped[str] = mapped_column(String(160), nullable=False)
    description: Mapped[str | None] = mapped_column(String(500))
    public_token_hash: Mapped[str] = mapped_column(String(64), nullable=False)
    public_token_prefix: Mapped[str] = mapped_column(String(12), nullable=False)
    qr_kind: Mapped[str] = mapped_column(String(32), nullable=False)
    resource_type: Mapped[str] = mapped_column(String(64), nullable=False)
    resource_reference: Mapped[str] = mapped_column(String(255), nullable=False)
    owner_app: Mapped[str] = mapped_column(String(64), nullable=False)
    action_key: Mapped[str | None] = mapped_column(String(64))
    policy_json: Mapped[dict] = mapped_column("policy", JSON, nullable=False, default=dict)
    status: Mapped[str] = mapped_column(String(24), nullable=False, default="active")
    valid_from: Mapped[datetime | None] = mapped_column(DateTime)
    expires_at: Mapped[datetime | None] = mapped_column(DateTime)
    max_scans: Mapped[int | None] = mapped_column(Integer)
    max_successful_uses: Mapped[int | None] = mapped_column(Integer)
    scan_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
    successful_use_count: Mapped[int] = mapped_column(Integer, nullable=False, default=0)
    requires_authentication: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)
    authentication_purpose: Mapped[str | None] = mapped_column(String(64))
    created_by: Mapped[str | None] = mapped_column(String(128))
    created_at: Mapped[datetime] = mapped_column(DateTime, nullable=False, default=datetime.utcnow)
    activated_at: Mapped[datetime | None] = mapped_column(DateTime)
    suspended_at: Mapped[datetime | None] = mapped_column(DateTime)
    revoked_at: Mapped[datetime | None] = mapped_column(DateTime)
    revoked_by: Mapped[str | None] = mapped_column(String(128))
    revoke_reason: Mapped[str | None] = mapped_column(String(255))
    replaced_by_qr_id: Mapped[str | None] = mapped_column(String(36), ForeignKey("qr_records.qr_id"))
    replaces_qr_id: Mapped[str | None] = mapped_column(String(36), ForeignKey("qr_records.qr_id"))
    last_scanned_at: Mapped[datetime | None] = mapped_column(DateTime)
    last_successful_use_at: Mapped[datetime | None] = mapped_column(DateTime)
    metadata_json: Mapped[dict] = mapped_column("metadata", JSON, nullable=False, default=dict)

class QRResolution(Base):
    __tablename__ = "qr_resolutions"
    __table_args__ = (Index("ix_qr_resolution_hash", "resolution_token_hash", unique=True), Index("ix_qr_resolution_correlation", "tenant_id", "correlation_id"))
    resolution_id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid)
    tenant_id: Mapped[str] = mapped_column(String(64), ForeignKey("tenants.tenant_id"), nullable=False)
    qr_id: Mapped[str] = mapped_column(String(36), ForeignKey("qr_records.qr_id"), nullable=False, index=True)
    resolution_token_hash: Mapped[str] = mapped_column(String(64), nullable=False)
    owner_app: Mapped[str] = mapped_column(String(64), nullable=False)
    action_key: Mapped[str | None] = mapped_column(String(64))
    resource_type: Mapped[str] = mapped_column(String(64), nullable=False)
    resource_reference: Mapped[str] = mapped_column(String(255), nullable=False)
    authenticated_subject_id: Mapped[str | None] = mapped_column(String(128))
    challenge_id: Mapped[str | None] = mapped_column(String(128))
    status: Mapped[str] = mapped_column(String(24), nullable=False)
    created_at: Mapped[datetime] = mapped_column(DateTime, nullable=False, default=datetime.utcnow)
    expires_at: Mapped[datetime] = mapped_column(DateTime, nullable=False)
    consumed_at: Mapped[datetime | None] = mapped_column(DateTime)
    correlation_id: Mapped[str] = mapped_column(String(128), nullable=False)

class QRAppPermission(Base):
    __tablename__ = "qr_app_permissions"
    __table_args__ = (UniqueConstraint("tenant_id", "requesting_app", name="uq_qr_permission_app"),)
    permission_id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid)
    tenant_id: Mapped[str] = mapped_column(String(64), ForeignKey("tenants.tenant_id"), nullable=False)
    requesting_app: Mapped[str] = mapped_column(String(64), nullable=False)
    enabled: Mapped[bool] = mapped_column(Boolean, nullable=False, default=True)
    operations_json: Mapped[list] = mapped_column("operations", JSON, nullable=False, default=list)
    resource_types_json: Mapped[list] = mapped_column("resource_types", JSON, nullable=False, default=list)
    action_keys_json: Mapped[list] = mapped_column("action_keys", JSON, nullable=False, default=list)
    may_manage_other_apps: Mapped[bool] = mapped_column(Boolean, nullable=False, default=False)

class QRIdempotency(Base):
    __tablename__ = "qr_idempotency"
    __table_args__ = (UniqueConstraint("tenant_id", "requesting_app", "operation", "idempotency_key", name="uq_qr_idempotency_scope"),)
    idempotency_id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid)
    tenant_id: Mapped[str] = mapped_column(String(64), nullable=False)
    requesting_app: Mapped[str] = mapped_column(String(64), nullable=False)
    operation: Mapped[str] = mapped_column(String(64), nullable=False)
    idempotency_key: Mapped[str] = mapped_column(String(128), nullable=False)
    request_hash: Mapped[str] = mapped_column(String(64), nullable=False)
    response_json: Mapped[dict] = mapped_column("response", JSON, nullable=False)
    created_at: Mapped[datetime] = mapped_column(DateTime, nullable=False, default=datetime.utcnow)

class QRAuditEvent(Base):
    __tablename__ = "qr_audit_events"
    __table_args__ = (Index("ix_qr_audit_scope", "tenant_id", "qr_id", "created_at"),)
    event_id: Mapped[str] = mapped_column(String(36), primary_key=True, default=_uuid)
    tenant_id: Mapped[str] = mapped_column(String(64), nullable=False)
    qr_id: Mapped[str | None] = mapped_column(String(36))
    resolution_id: Mapped[str | None] = mapped_column(String(36))
    event: Mapped[str] = mapped_column(String(64), nullable=False)
    requesting_app: Mapped[str | None] = mapped_column(String(64))
    result: Mapped[str] = mapped_column(String(32), nullable=False)
    correlation_id: Mapped[str | None] = mapped_column(String(128))
    details_json: Mapped[dict] = mapped_column("details", JSON, nullable=False, default=dict)
    created_at: Mapped[datetime] = mapped_column(DateTime, nullable=False, default=datetime.utcnow)
