"""
SQLAlchemy models for the Document Translation API
"""

import uuid
from datetime import datetime, timezone
import warnings

from sqlalchemy import (
    Column,
    String,
    Integer,
    Float,
    Boolean,
    DateTime,
    Text,
    ForeignKey,
    Enum,
    Index,
    JSON,
    BigInteger,
    CheckConstraint,
)
from sqlalchemy.orm import relationship, declarative_base
import enum


def _utcnow() -> datetime:
    return datetime.now(timezone.utc)


Base = declarative_base()


def generate_uuid():
    """Generate a new UUID string"""
    return str(uuid.uuid4())


def generate_uuid_value():
    """Generate a new UUID value for PostgreSQL UUID column"""
    return uuid.uuid4()


class PlanType(str, enum.Enum):
    FREE = "free"
    STARTER = "starter"
    PRO = "pro"
    BUSINESS = "business"
    ENTERPRISE = "enterprise"


class SubscriptionStatus(str, enum.Enum):
    ACTIVE = "active"
    CANCELED = "canceled"
    PAST_DUE = "past_due"
    TRIALING = "trialing"
    PAUSED = "paused"


class User(Base):
    """User model for authentication and billing"""

    __tablename__ = "users"

    id = Column(String(36), primary_key=True, default=generate_uuid)
    email = Column(String(255), unique=True, nullable=False, index=True)
    name = Column(String(255), nullable=False)
    hashed_password = Column(String(255), nullable=False)

    tier = Column(String(10), default="free", nullable=False)
    daily_translation_count = Column(Integer, default=0, nullable=False)

    email_verified = Column(Boolean, default=False)
    is_active = Column(Boolean, default=True)
    avatar_url = Column(String(500), nullable=True)

    plan = Column(Enum(PlanType), default=PlanType.FREE)
    subscription_status = Column(
        Enum(SubscriptionStatus), default=SubscriptionStatus.ACTIVE
    )

    stripe_customer_id = Column(String(255), nullable=True, index=True)
    stripe_subscription_id = Column(String(255), nullable=True)
    subscription_ends_at = Column(DateTime, nullable=True)
    cancel_at_period_end = Column(Boolean, default=False, nullable=False)

    reset_token = Column(String(255), nullable=True)
    reset_token_expires = Column(DateTime, nullable=True)

    docs_translated_this_month = Column(Integer, default=0)
    pages_translated_this_month = Column(Integer, default=0)
    api_calls_this_month = Column(Integer, default=0)
    extra_credits = Column(Integer, default=0)
    usage_reset_date = Column(DateTime, default=_utcnow)

    created_at = Column(DateTime, default=_utcnow)
    updated_at = Column(DateTime, default=_utcnow, onupdate=_utcnow)
    last_login_at = Column(DateTime, nullable=True)

    translations = relationship("Translation", back_populates="user", lazy="select")
    api_keys = relationship("ApiKey", back_populates="user", lazy="select")

    __table_args__ = (
        CheckConstraint("tier IN ('free', 'starter', 'pro', 'business', 'enterprise')", name="ck_users_tier"),
        Index("ix_users_email_active", "email", "is_active"),
        Index("ix_users_stripe_customer", "stripe_customer_id"),
    )

    @property
    def password_hash(self) -> str:
        warnings.warn(
            "password_hash is deprecated, use hashed_password instead",
            DeprecationWarning,
            stacklevel=2,
        )
        return self.hashed_password

    @password_hash.setter
    def password_hash(self, value: str) -> None:
        warnings.warn(
            "password_hash is deprecated, use hashed_password instead",
            DeprecationWarning,
            stacklevel=2,
        )
        self.hashed_password = value

    def to_dict(self) -> dict:
        return {
            "id": self.id,
            "email": self.email,
            "name": self.name,
            "avatar_url": self.avatar_url,
            "tier": self.tier,
            "plan": self.plan.value if self.plan else "free",
            "subscription_status": self.subscription_status.value
            if self.subscription_status
            else "active",
            "daily_translation_count": self.daily_translation_count,
            "docs_translated_this_month": self.docs_translated_this_month,
            "pages_translated_this_month": self.pages_translated_this_month,
            "api_calls_this_month": self.api_calls_this_month,
            "extra_credits": self.extra_credits,
            "email_verified": self.email_verified,
            "created_at": self.created_at.isoformat() if self.created_at else None,
        }


class Translation(Base):
    """Translation history for analytics and billing"""

    __tablename__ = "translations"

    id = Column(String(36), primary_key=True, default=generate_uuid)
    user_id = Column(
        String(36), ForeignKey("users.id", ondelete="CASCADE"), nullable=False
    )

    # File info
    original_filename = Column(String(255), nullable=False)
    file_type = Column(String(20), nullable=False)  # xlsx, docx, pptx
    file_size_bytes = Column(BigInteger, default=0)
    page_count = Column(Integer, default=0)

    # Translation details
    source_language = Column(String(10), default="auto")
    target_language = Column(String(10), nullable=False)
    provider = Column(String(50), nullable=False)  # google, ollama, etc.

    # Processing info
    status = Column(
        String(20), default="pending"
    )  # pending, processing, completed, failed
    error_message = Column(Text, nullable=True)
    processing_time_ms = Column(Integer, nullable=True)

    # Cost tracking (for paid providers)
    characters_translated = Column(Integer, default=0)
    estimated_cost_usd = Column(Float, default=0.0)

    # Timestamps
    created_at = Column(DateTime, default=_utcnow)
    completed_at = Column(DateTime, nullable=True)

    # Relationship
    user = relationship("User", back_populates="translations")

    # Indexes
    __table_args__ = (
        Index("ix_translations_user_date", "user_id", "created_at"),
        Index("ix_translations_status", "status"),
    )

    def to_dict(self) -> dict:
        return {
            "id": self.id,
            "original_filename": self.original_filename,
            "file_type": self.file_type,
            "file_size_bytes": self.file_size_bytes,
            "page_count": self.page_count,
            "source_language": self.source_language,
            "target_language": self.target_language,
            "provider": self.provider,
            "status": self.status,
            "processing_time_ms": self.processing_time_ms,
            "characters_translated": self.characters_translated,
            "created_at": self.created_at.isoformat() if self.created_at else None,
            "completed_at": self.completed_at.isoformat()
            if self.completed_at
            else None,
        }


class ApiKey(Base):
    """API keys for programmatic access"""

    __tablename__ = "api_keys"

    id = Column(String(36), primary_key=True, default=generate_uuid)
    user_id = Column(
        String(36), ForeignKey("users.id", ondelete="CASCADE"), nullable=False
    )

    # Key info
    name = Column(String(100), nullable=False)  # User-friendly name
    key_hash = Column(String(255), nullable=False)  # SHA256 of the key
    key_prefix = Column(String(10), nullable=False)  # First 8 chars for identification

    # Permissions
    is_active = Column(Boolean, default=True)
    scopes = Column(JSON, default=list)  # ["translate", "read", "write"]

    # Usage tracking
    last_used_at = Column(DateTime, nullable=True)
    usage_count = Column(Integer, default=0)

    # Timestamps
    created_at = Column(DateTime, default=_utcnow)
    expires_at = Column(DateTime, nullable=True)
    revoked_at = Column(DateTime, nullable=True)  # Set when is_active=False

    # Relationship
    user = relationship("User", back_populates="api_keys")

    # Indexes
    __table_args__ = (
        Index("ix_api_keys_prefix", "key_prefix"),
        Index("ix_api_keys_hash", "key_hash"),
    )

    def to_dict(self) -> dict:
        return {
            "id": self.id,
            "name": self.name,
            "key_prefix": self.key_prefix,
            "is_active": self.is_active,
            "scopes": self.scopes,
            "last_used_at": self.last_used_at.isoformat()
            if self.last_used_at
            else None,
            "usage_count": self.usage_count,
            "created_at": self.created_at.isoformat() if self.created_at else None,
            "expires_at": self.expires_at.isoformat() if self.expires_at else None,
        }


class UsageLog(Base):
    """Daily usage aggregation for billing and analytics"""

    __tablename__ = "usage_logs"

    id = Column(String(36), primary_key=True, default=generate_uuid)
    user_id = Column(
        String(36), ForeignKey("users.id", ondelete="CASCADE"), nullable=False
    )

    # Date (for daily aggregation)
    date = Column(DateTime, nullable=False, index=True)

    # Aggregated counts
    documents_count = Column(Integer, default=0)
    pages_count = Column(Integer, default=0)
    characters_count = Column(BigInteger, default=0)
    api_calls_count = Column(Integer, default=0)

    # By provider breakdown (JSON)
    provider_breakdown = Column(JSON, default=dict)

    # Indexes
    __table_args__ = (Index("ix_usage_logs_user_date", "user_id", "date", unique=True),)


class PaymentHistory(Base):
    """Payment and invoice history"""

    __tablename__ = "payment_history"

    id = Column(String(36), primary_key=True, default=generate_uuid)
    user_id = Column(
        String(36), ForeignKey("users.id", ondelete="CASCADE"), nullable=False
    )

    # Stripe info
    stripe_payment_intent_id = Column(String(255), nullable=True)
    stripe_invoice_id = Column(String(255), nullable=True)

    # Payment details
    amount_cents = Column(Integer, nullable=False)
    currency = Column(String(3), default="usd")
    payment_type = Column(String(50), nullable=False)  # subscription, credits, one_time
    status = Column(String(20), nullable=False)  # succeeded, failed, pending, refunded

    # Description
    description = Column(String(255), nullable=True)

    # Timestamps
    created_at = Column(DateTime, default=_utcnow)

    # Indexes
    __table_args__ = (Index("ix_payment_history_user", "user_id", "created_at"),)


class Glossary(Base):
    """User's glossary containing source->target term pairs.
    Story 3.9: Glossaires - Endpoint CRUD
    """

    __tablename__ = "glossaries"

    id = Column(String(36), primary_key=True, default=generate_uuid)
    user_id = Column(
        String(36), ForeignKey("users.id", ondelete="CASCADE"), nullable=False
    )
    # Optional: workspace this glossary is shared with (owner still administers it)
    workspace_id = Column(String(36), nullable=True)
    name = Column(String(255), nullable=False)
    source_language = Column(String(10), nullable=False, default="fr")
    target_language = Column(String(10), nullable=True, default="en")
    template_id = Column(String(50), nullable=True)
    created_at = Column(DateTime, default=_utcnow)
    updated_at = Column(DateTime, default=_utcnow, onupdate=_utcnow)

    # Relationship
    terms = relationship(
        "GlossaryTerm", back_populates="glossary", cascade="all, delete-orphan"
    )

    # Indexes
    __table_args__ = (
        Index("ix_glossaries_user_id", "user_id"),
        Index("ix_glossaries_template_id", "template_id"),
        Index("ix_glossaries_workspace", "workspace_id"),
    )

    def to_dict(self) -> dict:
        return {
            "id": self.id,
            "user_id": self.user_id,
            "workspace_id": self.workspace_id,
            "name": self.name,
            "source_language": self.source_language,
            "target_language": self.target_language,
            "template_id": self.template_id,
            "terms": [term.to_dict() for term in self.terms] if self.terms else [],
            "created_at": self.created_at.isoformat() if self.created_at else None,
            "updated_at": self.updated_at.isoformat() if self.updated_at else None,
        }


class GlossaryTerm(Base):
    """Single term pair in a glossary.
    Story 3.9: Glossaires - Endpoint CRUD
    """

    __tablename__ = "glossary_terms"

    id = Column(String(36), primary_key=True, default=generate_uuid)
    glossary_id = Column(
        String(36), ForeignKey("glossaries.id", ondelete="CASCADE"), nullable=False
    )
    source = Column(String(500), nullable=False)
    target = Column(String(500), nullable=False)
    translations = Column(JSON, nullable=True, default=dict)
    created_at = Column(DateTime, default=_utcnow)

    # Relationship
    glossary = relationship("Glossary", back_populates="terms")

    # Indexes
    __table_args__ = (Index("ix_glossary_terms_glossary_id", "glossary_id"),)

    def to_dict(self) -> dict:
        return {
            "id": self.id,
            "source": self.source,
            "target": self.target,
            "translations": self.translations or {},
            "created_at": self.created_at.isoformat() if self.created_at else None,
        }


class CustomPrompt(Base):
    """User's custom prompts for LLM translation context.
    Story 3.11: Custom Prompts - Endpoint CRUD
    """

    __tablename__ = "custom_prompts"

    id = Column(String(36), primary_key=True, default=generate_uuid)
    user_id = Column(
        String(36), ForeignKey("users.id", ondelete="CASCADE"), nullable=False
    )
    name = Column(String(255), nullable=False)
    content = Column(Text, nullable=False)
    created_at = Column(DateTime, default=_utcnow)
    updated_at = Column(DateTime, default=_utcnow, onupdate=_utcnow)

    # Indexes
    __table_args__ = (Index("ix_custom_prompts_user_id", "user_id"),)

    def to_dict(self) -> dict:
        return {
            "id": self.id,
            "user_id": self.user_id,
            "name": self.name,
            "content": self.content,
            "created_at": self.created_at.isoformat() if self.created_at else None,
            "updated_at": self.updated_at.isoformat() if self.updated_at else None,
        }


class TranslationSegment(Base):
    """One translatable unit of a finished job (review foundation).

    Segments persist (source, translation) pairs per job so reviewers can
    edit/approve them side-by-side, rebuild the document with the reviewed
    text, and export/import XLIFF.
    """

    __tablename__ = "translation_segments"

    id = Column(String(36), primary_key=True, default=generate_uuid)
    job_id = Column(String(64), nullable=False)
    user_id = Column(
        String(36), ForeignKey("users.id", ondelete="CASCADE"), nullable=False
    )
    segment_index = Column(Integer, nullable=False, default=0)
    source_text = Column(Text, nullable=False)
    translated_text = Column(Text, nullable=False, default="")
    # pending | approved | edited
    status = Column(String(20), nullable=False, default="pending")
    # Reviewer's edit (used for rebuild when status == "edited")
    reviewed_text = Column(Text, nullable=True)
    is_heading = Column(Boolean, nullable=False, default=False)
    created_at = Column(DateTime, default=_utcnow)
    updated_at = Column(DateTime, default=_utcnow, onupdate=_utcnow)

    __table_args__ = (
        Index("ix_segments_job_index", "job_id", "segment_index"),
        Index("ix_segments_user", "user_id"),
        Index("ix_segments_status", "job_id", "status"),
    )

    def to_dict(self) -> dict:
        return {
            "id": self.id,
            "job_id": self.job_id,
            "segment_index": self.segment_index,
            "source_text": self.source_text,
            "translated_text": self.translated_text,
            "status": self.status,
            "reviewed_text": self.reviewed_text,
            "is_heading": self.is_heading,
            "created_at": self.created_at.isoformat() if self.created_at else None,
            "updated_at": self.updated_at.isoformat() if self.updated_at else None,
        }


class Workspace(Base):
    """Team workspace: shared glossaries + seat-based membership.

    Seats are enforced from the owner's plan (Business = 5 seats).
    """

    __tablename__ = "workspaces"

    id = Column(String(36), primary_key=True, default=generate_uuid)
    name = Column(String(255), nullable=False)
    owner_id = Column(
        String(36), ForeignKey("users.id", ondelete="CASCADE"), nullable=False
    )
    created_at = Column(DateTime, default=_utcnow)

    members = relationship(
        "WorkspaceMember", back_populates="workspace", cascade="all, delete-orphan"
    )

    __table_args__ = (Index("ix_workspaces_owner", "owner_id"),)

    def to_dict(self) -> dict:
        return {
            "id": self.id,
            "name": self.name,
            "owner_id": self.owner_id,
            "member_count": len(self.members) if self.members else 0,
            "members": [m.to_dict() for m in self.members] if self.members else [],
            "created_at": self.created_at.isoformat() if self.created_at else None,
        }


class WorkspaceMember(Base):
    """Membership row linking a user to a workspace with a role."""

    __tablename__ = "workspace_members"

    id = Column(String(36), primary_key=True, default=generate_uuid)
    workspace_id = Column(
        String(36), ForeignKey("workspaces.id", ondelete="CASCADE"), nullable=False
    )
    user_id = Column(
        String(36), ForeignKey("users.id", ondelete="CASCADE"), nullable=False
    )
    # owner | admin | member
    role = Column(String(20), nullable=False, default="member")
    created_at = Column(DateTime, default=_utcnow)

    workspace = relationship("Workspace", back_populates="members")

    __table_args__ = (
        Index("ix_workspace_members_workspace", "workspace_id"),
        Index("ix_workspace_members_user", "user_id"),
        # UniqueConstraint imported lazily below if needed; enforced in app layer
    )

    def to_dict(self) -> dict:
        return {
            "id": self.id,
            "workspace_id": self.workspace_id,
            "user_id": self.user_id,
            "role": self.role,
            "created_at": self.created_at.isoformat() if self.created_at else None,
        }
