# src/fmatch/saas/model_defs/reporting_models.py
from __future__ import annotations
from sqlalchemy import (
    Column,
    DateTime,
    JSON,
    Index,
)
from sqlmodel import Field
from datetime import datetime
from typing import Optional, Dict, Any
from fmatch.saas.db import Base
import uuid


# === ChangeSet (batch container) ===
class ChangeSet(Base, table=True):
    __tablename__ = "change_sets"  # <- keep this spelling
    __table_args__ = (
        Index(
            "ix_changesets_account_status_time", "account_id", "status", "created_at"
        ),
        {"extend_existing": True},
    )

    id: str = Field(
        primary_key=True, default_factory=lambda: str(uuid.uuid4())
    )  # e.g. "cs_<uuid12>"
    account_id: str = Field(index=True)
    name: Optional[str] = Field(default=None)
    type: str = Field(index=True)  # l2a_apply|dedupe_merge|routing_assign|...
    source: str = Field(default="system")
    actor_type: str = Field(default="system")
    actor_id: Optional[str] = Field(default=None)
    scope: Optional[Dict[str, Any]] = Field(default=None, sa_column=Column(JSON))
    policy_id: Optional[str] = Field(default=None)
    status: str = Field(default="open")

    attempted_count: int = Field(default=0)
    applied_count: int = Field(default=0)
    failed_count: int = Field(default=0)

    created_at: datetime = Field(
        default_factory=datetime.utcnow, sa_column=Column(DateTime, index=True)
    )
    finalized_at: Optional[datetime] = Field(default=None)


# === ChangeEvent (field-level) ===
class ChangeEvent(Base, table=True):
    __tablename__ = "change_events"
    id: str = Field(primary_key=True, default_factory=lambda: str(uuid.uuid4()))
    account_id: str = Field(index=True)
    changeset_id: str = Field(foreign_key="change_sets.id", index=True)

    # Ordering & scale
    sequence_num: int = Field(index=True)  # global sequence
    parent_event_id: Optional[str] = Field(default=None)
    partition_key: str = Field(index=True)  # e.g. 2025-34 (ISO week)

    # Target & operation
    object_type: str = Field(index=True)  # Lead | Account | Contact | RoutingDecision
    object_id: str = Field(index=True)
    op: str = Field(index=True)  # update_field | merge | unmerge | create | delete
    field: Optional[str] = Field(default=None)
    before_value: Optional[str] = Field(default=None)
    after_value: Optional[str] = Field(default=None)

    # Evidence / context
    confidence: Optional[float] = Field(default=None)
    tier: Optional[str] = Field(default=None)
    suggestion_id: Optional[str] = Field(default=None)  # L2A suggestion id
    reason_text: Optional[str] = Field(default=None)
    field_score_details: list = Field(default_factory=list, sa_column=Column(JSON))

    # Actors & lifecycle
    actor_type: str = Field(index=True)  # user | system
    actor_id: Optional[str] = Field(default=None)
    applied_at: datetime = Field(
        default_factory=datetime.utcnow, sa_column=Column(DateTime, index=True)
    )
    reverted_at: Optional[datetime] = Field(default=None)
    revert_changeset_id: Optional[str] = Field(default=None)
    external_ref: Optional[str] = Field(default=None)  # e.g. Salesforce write id
    status: str = Field(
        default="applied", index=True
    )  # applied | skipped | failed | reverted

    # Security & tamper evidence
    contains_pii: bool = Field(default=False)
    pii_fields: list = Field(default_factory=list, sa_column=Column(JSON))
    checksum: str = Field(default="", index=True)

    created_at: datetime = Field(
        default_factory=datetime.utcnow, sa_column=Column(DateTime, index=True)
    )

    __table_args__ = (
        Index(
            "ix_change_events_object_seq", "object_type", "object_id", "sequence_num"
        ),
        Index("ix_change_events_partition_created", "partition_key", "created_at"),
        Index("ix_change_events_changeset", "changeset_id"),
        Index("ix_change_events_status", "status"),
        Index("ix_change_events_account_created", "account_id", "created_at"),
        {"extend_existing": True},
    )


# === QA sampling & metrics ===
class QASample(Base, table=True):
    __tablename__ = "qa_samples"
    __table_args__ = {"extend_existing": True}
    id: str = Field(primary_key=True, default_factory=lambda: str(uuid.uuid4()))
    account_id: str = Field(index=True)
    event_id: str = Field(foreign_key="change_events.id", index=True)
    label: Optional[str] = Field(default=None)  # tp | fp | unknown
    reviewer_id: Optional[str] = Field(default=None)
    reviewed_at: Optional[datetime] = Field(default=None)
    created_at: datetime = Field(
        default_factory=datetime.utcnow, sa_column=Column(DateTime, index=True)
    )


class ReportingWatermark(Base, table=True):
    __tablename__ = "reporting_watermarks"
    __table_args__ = {"extend_existing": True}
    metric_name: str = Field(primary_key=True)
    last_processed_at: datetime = Field(
        default_factory=lambda: datetime.utcfromtimestamp(0)
    )
    last_event_id: Optional[str] = Field(default=None)
    last_sequence: Optional[int] = Field(default=None)


class MetricSnapshot(Base, table=True):
    __tablename__ = "metric_snapshots"
    __table_args__ = {"extend_existing": True}
    metric_key: str = Field(primary_key=True)  # e.g., l2a.acceptance.daily.2025-08-24
    account_id: str = Field(index=True)
    value: Dict[str, Any] = Field(
        default_factory=dict, sa_column=Column(JSON)
    )  # store dict payloads safely
    computed_at: datetime = Field(
        default_factory=datetime.utcnow, sa_column=Column(DateTime, index=True)
    )
    ttl_seconds: int = Field(default=3600)


class ChangeSubscription(Base, table=True):
    __tablename__ = "change_subscriptions"
    __table_args__ = {"extend_existing": True}
    id: str = Field(primary_key=True, default_factory=lambda: str(uuid.uuid4()))
    account_id: str = Field(index=True)
    user_id: str = Field(index=True)
    object_type: Optional[str] = Field(default=None)  # e.g., Account
    object_id: Optional[str] = Field(default=None)
    notify_on: list = Field(
        default_factory=list, sa_column=Column(JSON)
    )  # ["merge","owner_change"]


# Fallback counter when DB has no native sequence
class SequenceCounter(Base, table=True):
    __tablename__ = "sequence_counters"
    __table_args__ = {"extend_existing": True}
    name: str = Field(primary_key=True)
    value: int = Field(default=0)
