"""Connectors domain — SQLAlchemy models."""
from __future__ import annotations

import enum
from datetime import datetime
from typing import Optional
from uuid import UUID, uuid4

from sqlalchemy import ForeignKey, String, Text, UniqueConstraint
from sqlalchemy.dialects.postgresql import JSONB
from sqlalchemy.dialects.postgresql import UUID as PGUUID
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.sql import func
from sqlalchemy.types import DateTime

from src.core.database import Base


class ConnectorStatus(str, enum.Enum):
    active = "active"
    disabled = "disabled"
    preview = "preview"


class ConnectorConnectionStatus(str, enum.Enum):
    active = "active"
    disconnected = "disconnected"
    error = "error"
    pending = "pending"
    reauthentication_required = "reauthentication_required"


class ConnectorPermissionMode(str, enum.Enum):
    allow = "allow"
    deny = "deny"
    ask = "ask"


class Connector(Base):
    """Static connector catalog entry owned by Core."""

    __tablename__ = "connectors"

    id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), primary_key=True, default=uuid4)
    key: Mapped[str] = mapped_column(String(64), nullable=False, unique=True, index=True)
    name: Mapped[str] = mapped_column(String(120), nullable=False)
    category: Mapped[str] = mapped_column(String(64), nullable=False)
    auth_type: Mapped[str] = mapped_column(String(32), nullable=False)
    status: Mapped[str] = mapped_column(String(20), nullable=False, default="active")
    icon: Mapped[Optional[str]] = mapped_column(String(120), nullable=True)
    description: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    docs_url: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    metadata_json: Mapped[Optional[dict]] = mapped_column(JSONB, 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()
    )


class ConnectorAction(Base):
    """Provider-shaped action contract, not a provider SDK wrapper."""

    __tablename__ = "connector_actions"

    id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), primary_key=True, default=uuid4)
    connector_id: Mapped[UUID] = mapped_column(
        PGUUID(as_uuid=True), ForeignKey("connectors.id", ondelete="CASCADE"), nullable=False, index=True
    )
    action_key: Mapped[str] = mapped_column(String(80), nullable=False)
    slug: Mapped[str] = mapped_column(String(160), nullable=False, unique=True, index=True)
    name: Mapped[str] = mapped_column(String(160), nullable=False)
    description: Mapped[Optional[str]] = mapped_column(Text, nullable=True)
    input_schema: Mapped[dict] = mapped_column(JSONB, nullable=False, default=dict)
    output_schema: Mapped[dict] = mapped_column(JSONB, nullable=False, default=dict)
    execution_mode: Mapped[str] = mapped_column(String(20), nullable=False, default="sync")
    required_scopes: Mapped[list] = mapped_column(JSONB, nullable=False, default=list)
    required_capabilities: Mapped[list] = mapped_column(JSONB, nullable=False, default=list)
    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()
    )

    __table_args__ = (
        UniqueConstraint("connector_id", "action_key", name="uq_connector_actions_connector_key"),
    )


class ConnectorTrigger(Base):
    """Provider-shaped inbound event contract."""

    __tablename__ = "connector_triggers"

    id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), primary_key=True, default=uuid4)
    connector_id: Mapped[UUID] = mapped_column(
        PGUUID(as_uuid=True), ForeignKey("connectors.id", ondelete="CASCADE"), nullable=False, index=True
    )
    trigger_key: Mapped[str] = mapped_column(String(100), nullable=False)
    event_type: Mapped[str] = mapped_column(String(180), nullable=False, index=True)
    name: Mapped[str] = mapped_column(String(160), nullable=False)
    webhook_required: Mapped[bool] = mapped_column(nullable=False, default=True)
    polling_supported: Mapped[bool] = mapped_column(nullable=False, default=False)
    schema: Mapped[dict] = mapped_column(JSONB, nullable=False, default=dict)
    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()
    )

    __table_args__ = (
        UniqueConstraint("connector_id", "trigger_key", name="uq_connector_triggers_connector_key"),
    )


class ConnectorConnection(Base):
    """Workspace/project instance of a connector.

    Raw secret values are stored encrypted in Core only. Cloud receives an
    opaque auth_data_ref/secret_ref and mirrored non-secret metadata.
    """

    __tablename__ = "connector_connections"

    provider_connection_id: Mapped[Optional[UUID]] = mapped_column(
        PGUUID(as_uuid=True), ForeignKey("provider_connections.id", ondelete="RESTRICT"), nullable=True, index=True
    )

    id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), primary_key=True, default=uuid4)
    connector_id: Mapped[UUID] = mapped_column(
        PGUUID(as_uuid=True), ForeignKey("connectors.id", ondelete="RESTRICT"), nullable=False, index=True
    )
    workspace_id: Mapped[UUID] = mapped_column(
        PGUUID(as_uuid=True), ForeignKey("workspaces.id", ondelete="CASCADE"), nullable=False, index=True
    )
    project_id: Mapped[Optional[UUID]] = mapped_column(
        PGUUID(as_uuid=True), ForeignKey("projects.id", ondelete="CASCADE"), nullable=True, index=True
    )
    name: Mapped[str] = mapped_column(String(80), nullable=False)
    status: Mapped[str] = mapped_column(String(20), nullable=False, default="active")
    auth_data_ref: Mapped[Optional[str]] = mapped_column(String(220), nullable=True)
    scopes: Mapped[list] = mapped_column(JSONB, nullable=False, default=list)
    config_json: Mapped[Optional[dict]] = mapped_column(JSONB, nullable=True)
    secrets_enc: Mapped[Optional[dict]] = mapped_column(JSONB, 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()
    )

    __table_args__ = (
        UniqueConstraint("project_id", "name", name="uq_connector_connections_project_name"),
    )


class WorkspaceConnectorDefault(Base):
    """Workspace-level credential template for a connector.

    Not a live connection — stored credentials are copied into a new project-scoped
    ConnectorConnection on demand. Prevents re-entering the same keys for every project.
    """

    __tablename__ = "workspace_connector_defaults"

    id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), primary_key=True, default=uuid4)
    workspace_id: Mapped[UUID] = mapped_column(
        PGUUID(as_uuid=True), ForeignKey("workspaces.id", ondelete="CASCADE"), nullable=False, index=True
    )
    connector_key: Mapped[str] = mapped_column(String(64), nullable=False)
    config_json: Mapped[Optional[dict]] = mapped_column(JSONB, nullable=True)
    secrets_enc: Mapped[Optional[dict]] = mapped_column(JSONB, nullable=True)
    scopes: Mapped[list] = mapped_column(JSONB, nullable=False, default=list)
    default_permissions: Mapped[dict] = mapped_column(JSONB, nullable=False, default=dict)
    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()
    )

    __table_args__ = (
        UniqueConstraint(
            "workspace_id", "connector_key", name="uq_workspace_connector_defaults_ws_key"
        ),
    )


class ConnectorPermission(Base):
    """Per-connection action policy decided by Core."""

    __tablename__ = "connector_permissions"

    id: Mapped[UUID] = mapped_column(PGUUID(as_uuid=True), primary_key=True, default=uuid4)
    connection_id: Mapped[UUID] = mapped_column(
        PGUUID(as_uuid=True), ForeignKey("connector_connections.id", ondelete="CASCADE"), nullable=False, index=True
    )
    action_slug: Mapped[str] = mapped_column(String(160), nullable=False)
    mode: Mapped[str] = mapped_column(String(12), nullable=False, default="deny")
    policy_json: Mapped[Optional[dict]] = mapped_column(JSONB, 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()
    )

    __table_args__ = (
        UniqueConstraint("connection_id", "action_slug", name="uq_connector_permissions_connection_action"),
    )
