import uuid
from datetime import datetime
from typing import Optional

from sqlalchemy import DateTime, ForeignKey, Integer, String, Text, UniqueConstraint, func
from sqlalchemy.dialects.postgresql import JSONB, UUID
from sqlalchemy.orm import Mapped, mapped_column, relationship

from app.models.database import Base


class Agency(Base):
    """Agency/organization that users belong to."""
    __tablename__ = "agencies"

    id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    name: Mapped[str] = mapped_column(String(255), nullable=False, unique=True)
    created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())

    # Relationships
    users: Mapped[list["User"]] = relationship("User", back_populates="agency")
    campaigns: Mapped[list["Campaign"]] = relationship("Campaign", back_populates="agency")


class User(Base):
    """User account linked to Azure AD."""
    __tablename__ = "users"

    id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    azure_ad_oid: Mapped[str] = mapped_column(String(255), unique=True, nullable=False)
    email: Mapped[str] = mapped_column(String(255), nullable=False)
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    role: Mapped[str] = mapped_column(String(50), nullable=False, default="basic_user")
    agency_id: Mapped[Optional[uuid.UUID]] = mapped_column(UUID(as_uuid=True), ForeignKey("agencies.id"), nullable=True)
    created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())

    # Relationships
    agency: Mapped[Optional["Agency"]] = relationship("Agency", back_populates="users")
    campaigns: Mapped[list["Campaign"]] = relationship("Campaign", back_populates="created_by_user")
    proofs: Mapped[list["Proof"]] = relationship("Proof", back_populates="created_by_user")
    flagged_items: Mapped[list["FlaggedItem"]] = relationship("FlaggedItem", back_populates="submitter")
    resolved_items: Mapped[list["ResolvedItem"]] = relationship("ResolvedItem", back_populates="submitter")


class Campaign(Base):
    """Marketing campaign containing proofs."""
    __tablename__ = "campaigns"

    id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    name: Mapped[str] = mapped_column(String(255), nullable=False)
    workfront_id: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
    client_lead: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
    agency_lead: Mapped[Optional[str]] = mapped_column(String(255), nullable=True)
    brand_guidelines: Mapped[Optional[str]] = mapped_column(String(50), nullable=True)
    status: Mapped[str] = mapped_column(String(50), default="In Progress")
    agency_id: Mapped[Optional[uuid.UUID]] = mapped_column(UUID(as_uuid=True), ForeignKey("agencies.id"), nullable=True)
    created_by: Mapped[Optional[uuid.UUID]] = mapped_column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=True)
    created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())
    updated_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())

    # Relationships
    agency: Mapped[Optional["Agency"]] = relationship("Agency", back_populates="campaigns")
    created_by_user: Mapped[Optional["User"]] = relationship("User", back_populates="campaigns")
    proofs: Mapped[list["Proof"]] = relationship("Proof", back_populates="campaign", cascade="all, delete-orphan")


class Proof(Base):
    """Marketing proof/asset to be reviewed."""
    __tablename__ = "proofs"

    id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    campaign_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("campaigns.id", ondelete="CASCADE"), nullable=False)
    proof_name: Mapped[str] = mapped_column(String(255), nullable=False)
    channel: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
    sub_channel: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
    proof_type: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
    workfront_id: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
    created_by: Mapped[Optional[uuid.UUID]] = mapped_column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=True)
    created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())

    # Relationships
    campaign: Mapped["Campaign"] = relationship("Campaign", back_populates="proofs")
    created_by_user: Mapped[Optional["User"]] = relationship("User", back_populates="proofs")
    versions: Mapped[list["ProofVersion"]] = relationship("ProofVersion", back_populates="proof", cascade="all, delete-orphan", order_by="desc(ProofVersion.version)")

    __table_args__ = (
        UniqueConstraint("campaign_id", "proof_name", name="uq_campaign_proof_name"),
    )


class ProofVersion(Base):
    """Version of a proof with analysis results."""
    __tablename__ = "proof_versions"

    id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    proof_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("proofs.id", ondelete="CASCADE"), nullable=False)
    version: Mapped[int] = mapped_column(Integer, nullable=False)
    file_storage_key: Mapped[Optional[str]] = mapped_column(String(500), nullable=True)
    thumbnail_url: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    agent_review: Mapped[Optional[dict]] = mapped_column(JSONB, nullable=True)
    overall_status: Mapped[Optional[str]] = mapped_column(String(50), nullable=True)
    workfront_id: Mapped[Optional[str]] = mapped_column(String(100), nullable=True)
    created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())

    # Relationships
    proof: Mapped["Proof"] = relationship("Proof", back_populates="versions")
    flagged_items: Mapped[list["FlaggedItem"]] = relationship("FlaggedItem", back_populates="proof_version")
    resolved_items: Mapped[list["ResolvedItem"]] = relationship("ResolvedItem", back_populates="proof_version")
    error_items: Mapped[list["ErrorItem"]] = relationship("ErrorItem", back_populates="proof_version")

    __table_args__ = (
        UniqueConstraint("proof_id", "version", name="uq_proof_version"),
    )


class FlaggedItem(Base):
    """Record of a flagged issue on a proof version."""
    __tablename__ = "flagged_items"

    id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    proof_version_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("proof_versions.id"), nullable=False)
    agent_flagged: Mapped[str] = mapped_column(String(100), nullable=False)
    comments: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    submitter_id: Mapped[Optional[uuid.UUID]] = mapped_column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=True)
    created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())

    # Relationships
    proof_version: Mapped["ProofVersion"] = relationship("ProofVersion", back_populates="flagged_items")
    submitter: Mapped[Optional["User"]] = relationship("User", back_populates="flagged_items")


class ResolvedItem(Base):
    """Record of a resolved issue on a proof version."""
    __tablename__ = "resolved_items"

    id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    proof_version_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("proof_versions.id"), nullable=False)
    agent: Mapped[str] = mapped_column(String(100), nullable=False)
    issue: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    resolution: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    submitter_id: Mapped[Optional[uuid.UUID]] = mapped_column(UUID(as_uuid=True), ForeignKey("users.id"), nullable=True)
    created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())

    # Relationships
    proof_version: Mapped["ProofVersion"] = relationship("ProofVersion", back_populates="resolved_items")
    submitter: Mapped[Optional["User"]] = relationship("User", back_populates="resolved_items")


class ErrorItem(Base):
    """Record of an analysis error on a proof version."""
    __tablename__ = "error_items"

    id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    proof_version_id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), ForeignKey("proof_versions.id"), nullable=False)
    error_summary: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())

    # Relationships
    proof_version: Mapped["ProofVersion"] = relationship("ProofVersion", back_populates="error_items")


class DropdownOption(Base):
    """Configurable dropdown options for channels/sub-channels/proof types."""
    __tablename__ = "dropdown_options"

    id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
    option_type: Mapped[str] = mapped_column(String(50), nullable=False)  # 'channel', 'sub_channel', 'proof_type'
    parent_id: Mapped[Optional[uuid.UUID]] = mapped_column(UUID(as_uuid=True), ForeignKey("dropdown_options.id"), nullable=True)
    value: Mapped[str] = mapped_column(String(255), nullable=False)
    display_order: Mapped[int] = mapped_column(Integer, default=0)
    created_at: Mapped[datetime] = mapped_column(DateTime(timezone=True), server_default=func.now())

    # Self-referential relationship for hierarchy
    parent: Mapped[Optional["DropdownOption"]] = relationship("DropdownOption", remote_side=[id], back_populates="children")
    children: Mapped[list["DropdownOption"]] = relationship("DropdownOption", back_populates="parent")
