from __future__ import annotations

from datetime import datetime
from typing import Optional

from sqlalchemy import Column, DateTime, Text
from sqlmodel import Field

from fmatch.saas.db import Base


def _default_json() -> str:
    return "[]"


def _utcnow() -> datetime:
    """Return current UTC time as naive datetime (matches TIMESTAMP WITHOUT TIME ZONE)."""
    return datetime.utcnow()


class SalesforceSchemaIndexState(Base, table=True):
    """Tracks schema index freshness per org."""

    __tablename__ = "sf_schema_index_state"
    __table_args__ = {"extend_existing": True}

    org_id: str = Field(primary_key=True, max_length=64)
    schema_hash: Optional[str] = Field(default=None, max_length=64, index=True)
    quick_indexed_at: Optional[datetime] = Field(
        default=None, sa_column=Column(DateTime, nullable=True)
    )
    full_indexed_at: Optional[datetime] = Field(
        default=None, sa_column=Column(DateTime, nullable=True)
    )
    status: str = Field(default="idle", max_length=16, index=True)
    error_json: Optional[str] = Field(default=None, sa_column=Column(Text))
    in_progress: bool = Field(default=False)
    stage: Optional[str] = Field(default=None, max_length=16)
    runner_token: Optional[str] = Field(default=None, max_length=64)
    heartbeat_at: Optional[datetime] = Field(
        default=None, sa_column=Column(DateTime, nullable=True)
    )
    checkpoint_json: str = Field(default="{}", sa_column=Column(Text))
    fls_hash: Optional[str] = Field(default=None, max_length=64)
    updated_at: datetime = Field(
        default_factory=_utcnow,
        sa_column=Column(DateTime, default=_utcnow, onupdate=_utcnow),
    )


class SalesforceSchemaObject(Base, table=True):
    """Indexed Salesforce object metadata."""

    __tablename__ = "sf_schema_objects"
    __table_args__ = {"extend_existing": True}

    org_id: str = Field(primary_key=True, max_length=64)
    object_api: str = Field(primary_key=True, max_length=120)
    label: Optional[str] = Field(default=None, max_length=500)
    label_plural: Optional[str] = Field(default=None, max_length=255)
    is_custom: bool = Field(default=False, index=True)
    is_reportable: bool = Field(default=True, index=True)
    record_count: Optional[int] = Field(default=None, index=False)
    last_modified: Optional[datetime] = Field(
        default=None, sa_column=Column(DateTime, nullable=True)
    )
    # embedding: vector(768) column exists in DB but is excluded from ORM
    # to avoid SQLModel type issues. Use raw SQL for vector operations.
    schema_hash: Optional[str] = Field(default=None, max_length=64, index=True)
    indexed_at: datetime = Field(
        default_factory=_utcnow,
        sa_column=Column(DateTime, default=_utcnow),
    )


class SalesforceSchemaField(Base, table=True):
    """Indexed Salesforce field metadata."""

    __tablename__ = "sf_schema_fields"
    __table_args__ = {"extend_existing": True}

    org_id: str = Field(primary_key=True, max_length=64)
    object_api: str = Field(primary_key=True, max_length=120)
    field_api: str = Field(primary_key=True, max_length=200)
    label: Optional[str] = Field(default=None, max_length=255)
    help_text: Optional[str] = Field(default=None, sa_column=Column(Text))
    data_type: str = Field(max_length=64)
    precision: Optional[int] = Field(default=None)
    scale: Optional[int] = Field(default=None)
    length: Optional[int] = Field(default=None)
    is_custom: bool = Field(default=False, index=True)
    is_formula: bool = Field(default=False)
    is_calculated: bool = Field(default=False)
    is_picklist: bool = Field(default=False)
    picklist_json: str = Field(default="[]", sa_column=Column(Text))
    reference_to: Optional[str] = Field(default=None, sa_column=Column(Text))
    relationship_api: Optional[str] = Field(default=None, max_length=120)
    relationship_label: Optional[str] = Field(default=None, max_length=500)
    queryable: bool = Field(default=True, index=True)
    filterable: bool = Field(default=True, index=True)
    sortable: bool = Field(default=True)
    nillable: bool = Field(default=True)
    unique: bool = Field(default=False)
    calculated_formula: Optional[str] = Field(default=None, sa_column=Column(Text))
    # embedding: vector(768) column exists in DB but is excluded from ORM
    # to avoid SQLModel type issues. Use raw SQL for vector operations.
    schema_hash: Optional[str] = Field(default=None, index=True)
    indexed_at: datetime = Field(
        default_factory=_utcnow,
        sa_column=Column(DateTime, default=_utcnow),
    )


class SalesforceSchemaRelationship(Base, table=True):
    """Lookup relationship metadata."""

    __tablename__ = "sf_schema_relationships"
    __table_args__ = {"extend_existing": True}

    org_id: str = Field(primary_key=True, max_length=64)
    from_object: str = Field(primary_key=True, max_length=120)
    field_api: str = Field(primary_key=True, max_length=200)
    to_object: str = Field(max_length=120)
    relationship_api: Optional[str] = Field(default=None, max_length=120)
    cardinality: Optional[str] = Field(default=None, max_length=32)
    schema_hash: Optional[str] = Field(default=None, index=True)
    indexed_at: datetime = Field(
        default_factory=_utcnow,
        sa_column=Column(DateTime, default=_utcnow),
    )


class SalesforceSchemaTerm(Base, table=True):
    """Tokenised term mapping to fields for fast lookup."""

    __tablename__ = "sf_schema_terms"
    __table_args__ = {"extend_existing": True}

    org_id: str = Field(primary_key=True, max_length=64)
    term: str = Field(primary_key=True, max_length=120)
    field_ref: str = Field(primary_key=True, max_length=240)
    weight: float = Field(default=0.0, index=True)
    source: str = Field(default="label", max_length=32)
    schema_hash: Optional[str] = Field(default=None, index=True)
    indexed_at: datetime = Field(
        default_factory=_utcnow,
        sa_column=Column(DateTime, default=_utcnow),
    )


class SalesforceSchemaFieldUsage(Base, table=True):
    """Report usage counts gathered from Analytics API."""

    __tablename__ = "sf_schema_field_usage"
    __table_args__ = {"extend_existing": True}

    org_id: str = Field(primary_key=True, max_length=64)
    field_ref: str = Field(primary_key=True, max_length=240)
    report_count: int = Field(default=0)
    last_run_at: Optional[datetime] = Field(
        default=None, sa_column=Column(DateTime, nullable=True)
    )
    last_referenced_at: Optional[datetime] = Field(
        default=None, sa_column=Column(DateTime, nullable=True)
    )
    schema_hash: Optional[str] = Field(default=None, index=True)
    indexed_at: datetime = Field(
        default_factory=_utcnow,
        sa_column=Column(DateTime, default=_utcnow),
    )


class SalesforceSchemaFieldProfile(Base, table=True):
    """Profiling metrics derived from sampled data."""

    __tablename__ = "sf_schema_field_profiles"
    __table_args__ = {"extend_existing": True}

    org_id: str = Field(primary_key=True, max_length=64)
    field_ref: str = Field(primary_key=True, max_length=240)
    not_null_rate: Optional[float] = Field(default=None)
    distinct_ratio: Optional[float] = Field(default=None)
    top_values_json: str = Field(default=_default_json, sa_column=Column(Text))
    sample_values_json: str = Field(default=_default_json, sa_column=Column(Text))
    updated_at: datetime = Field(
        default_factory=_utcnow,
        sa_column=Column(DateTime, default=_utcnow),
    )


class SalesforceSchemaFieldAppUsage(Base, table=True):
    """Rolling usage counts from Copilot activity."""

    __tablename__ = "sf_schema_field_app_usage"
    __table_args__ = {"extend_existing": True}

    org_id: str = Field(primary_key=True, max_length=64)
    field_ref: str = Field(primary_key=True, max_length=240)
    query_count_30d: int = Field(default=0)
    preview_count_30d: int = Field(default=0)
    cooccur_json: str = Field(default="{}", sa_column=Column(Text))
    updated_at: datetime = Field(
        default_factory=_utcnow,
        sa_column=Column(DateTime, default=_utcnow),
    )


__all__ = [
    "SalesforceSchemaIndexState",
    "SalesforceSchemaObject",
    "SalesforceSchemaField",
    "SalesforceSchemaRelationship",
    "SalesforceSchemaTerm",
    "SalesforceSchemaFieldUsage",
    "SalesforceSchemaFieldProfile",
    "SalesforceSchemaFieldAppUsage",
]
