"""Initial schema: all ACE-F v1 tables.

Revision ID: 0001
Revises:
Create Date: 2026-03-12

Tables created:
- issuer_master, symbol_master: company reference data
- job_runs: pipeline execution tracking
- documents, document_exhibits: SEC filing metadata
- exhibit_cache: local exhibit text cache metadata
- events, event_parses: parsed event data
- macro_series, macro_observations: FRED macro data
- short_sale_daily: FINRA short volume data
- feature_snapshots: computed ML features
- order_plans: future trade plans (schema only in Phase 1)
- sync_checkpoints: FRED/FINRA sync state
"""
from __future__ import annotations

from collections.abc import Sequence

import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects.postgresql import JSONB, UUID

revision: str = "0001"
down_revision: str | None = None
branch_labels: str | Sequence[str] | None = None
depends_on: str | Sequence[str] | None = None


def upgrade() -> None:
    op.create_table(
        "issuer_master",
        sa.Column("issuer_id", sa.Text, primary_key=True),
        sa.Column("cik", sa.Text, nullable=True, unique=True),
        sa.Column("ticker", sa.Text, nullable=True),
        sa.Column("issuer_name", sa.Text, nullable=False),
        sa.Column("exchange", sa.Text, nullable=True),
        sa.Column("country_code", sa.Text, nullable=True),
        sa.Column("is_active", sa.Boolean, nullable=False, server_default=sa.text("true")),
        sa.Column(
            "created_at_utc",
            sa.DateTime(timezone=True),
            nullable=False,
            server_default=sa.text("now()"),
        ),
        sa.Column(
            "updated_at_utc",
            sa.DateTime(timezone=True),
            nullable=False,
            server_default=sa.text("now()"),
        ),
    )

    op.create_table(
        "symbol_master",
        sa.Column("symbol_id", sa.Text, primary_key=True),
        sa.Column(
            "issuer_id",
            sa.Text,
            sa.ForeignKey("issuer_master.issuer_id"),
            nullable=True,
        ),
        sa.Column("ticker", sa.Text, nullable=False),
        sa.Column("venue", sa.Text, nullable=True),
        sa.Column("asset_type", sa.Text, nullable=True),
        sa.Column("currency", sa.Text, nullable=True),
        sa.Column("start_date", sa.Date, nullable=True),
        sa.Column("end_date", sa.Date, nullable=True),
        sa.Column("is_primary", sa.Boolean, nullable=False, server_default=sa.text("true")),
        sa.Column(
            "created_at_utc",
            sa.DateTime(timezone=True),
            nullable=False,
            server_default=sa.text("now()"),
        ),
        sa.Column(
            "updated_at_utc",
            sa.DateTime(timezone=True),
            nullable=False,
            server_default=sa.text("now()"),
        ),
    )

    op.create_table(
        "job_runs",
        sa.Column("job_run_id", UUID(as_uuid=True), primary_key=True),
        sa.Column("job_name", sa.Text, nullable=False),
        sa.Column("source_name", sa.Text, nullable=True),
        sa.Column("run_date", sa.Date, nullable=True),
        sa.Column("status", sa.Text, nullable=False),
        sa.Column(
            "started_at_utc",
            sa.DateTime(timezone=True),
            nullable=False,
            server_default=sa.text("now()"),
        ),
        sa.Column("finished_at_utc", sa.DateTime(timezone=True), nullable=True),
        sa.Column("records_seen", sa.Integer, nullable=False, server_default=sa.text("0")),
        sa.Column("records_written", sa.Integer, nullable=False, server_default=sa.text("0")),
        sa.Column("records_skipped", sa.Integer, nullable=False, server_default=sa.text("0")),
        sa.Column("error_count", sa.Integer, nullable=False, server_default=sa.text("0")),
        sa.Column("error_summary", sa.Text, nullable=True),
        sa.Column("metadata_json", JSONB, nullable=False, server_default=sa.text("'{}'")),
    )
    op.create_index("ix_job_runs_job_name_run_date", "job_runs", ["job_name", "run_date"])

    op.create_table(
        "documents",
        sa.Column("document_id", sa.Text, primary_key=True),
        sa.Column("source_name", sa.Text, nullable=False),
        sa.Column(
            "issuer_id",
            sa.Text,
            sa.ForeignKey("issuer_master.issuer_id"),
            nullable=True,
        ),
        sa.Column(
            "symbol_id",
            sa.Text,
            sa.ForeignKey("symbol_master.symbol_id"),
            nullable=True,
        ),
        sa.Column("accession_no", sa.Text, nullable=True),
        sa.Column("form_type", sa.Text, nullable=False),
        sa.Column("filing_date", sa.Date, nullable=False),
        sa.Column("accepted_at_utc", sa.DateTime(timezone=True), nullable=True),
        sa.Column("primary_document_name", sa.Text, nullable=True),
        sa.Column("parsed_status", sa.Text, nullable=False, server_default=sa.text("'pending'")),
        sa.Column(
            "created_at_utc",
            sa.DateTime(timezone=True),
            nullable=False,
            server_default=sa.text("now()"),
        ),
        sa.Column(
            "updated_at_utc",
            sa.DateTime(timezone=True),
            nullable=False,
            server_default=sa.text("now()"),
        ),
        sa.UniqueConstraint("accession_no", "form_type", name="uq_documents_accession_form"),
    )
    op.create_index(
        "ix_documents_issuer_filing_date", "documents", ["issuer_id", "filing_date"]
    )
    op.create_index(
        "ix_documents_form_type_filing_date", "documents", ["form_type", "filing_date"]
    )

    op.create_table(
        "document_exhibits",
        sa.Column("exhibit_id", sa.Text, primary_key=True),
        sa.Column(
            "document_id",
            sa.Text,
            sa.ForeignKey("documents.document_id"),
            nullable=False,
        ),
        sa.Column("exhibit_code", sa.Text, nullable=False),
        sa.Column("exhibit_name", sa.Text, nullable=True),
        sa.Column(
            "created_at_utc",
            sa.DateTime(timezone=True),
            nullable=False,
            server_default=sa.text("now()"),
        ),
    )

    op.create_table(
        "exhibit_cache",
        sa.Column("id", sa.BigInteger, primary_key=True, autoincrement=True),
        sa.Column("accession_no", sa.Text, nullable=False),
        sa.Column("exhibit_type", sa.Text, nullable=False),
        sa.Column("content_hash", sa.Text, nullable=False),
        sa.Column("cache_path", sa.Text, nullable=False),
        sa.Column(
            "fetched_at_utc",
            sa.DateTime(timezone=True),
            nullable=False,
            server_default=sa.text("now()"),
        ),
        sa.UniqueConstraint(
            "accession_no", "exhibit_type", name="uq_exhibit_cache_accession_type"
        ),
    )

    op.create_table(
        "events",
        sa.Column("event_id", sa.Text, primary_key=True),
        sa.Column(
            "issuer_id",
            sa.Text,
            sa.ForeignKey("issuer_master.issuer_id"),
            nullable=True,
        ),
        sa.Column(
            "symbol_id",
            sa.Text,
            sa.ForeignKey("symbol_master.symbol_id"),
            nullable=True,
        ),
        sa.Column(
            "primary_document_id",
            sa.Text,
            sa.ForeignKey("documents.document_id"),
            nullable=False,
        ),
        sa.Column("event_type", sa.Text, nullable=False),
        sa.Column("event_direction", sa.Text, nullable=False),
        sa.Column("event_date", sa.Date, nullable=False),
        sa.Column("filed_at_utc", sa.DateTime(timezone=True), nullable=True),
        sa.Column("parser_version", sa.Text, nullable=False),
        sa.Column("parse_confidence", sa.Numeric, nullable=True),
        sa.Column("status", sa.Text, nullable=False, server_default=sa.text("'pending'")),
        sa.Column(
            "created_at_utc",
            sa.DateTime(timezone=True),
            nullable=False,
            server_default=sa.text("now()"),
        ),
        sa.Column(
            "updated_at_utc",
            sa.DateTime(timezone=True),
            nullable=False,
            server_default=sa.text("now()"),
        ),
    )
    op.create_index("ix_events_event_type_date", "events", ["event_type", "event_date"])
    op.create_index(
        "ix_events_primary_document_id", "events", ["primary_document_id"]
    )

    op.create_table(
        "event_parses",
        sa.Column("event_parse_id", sa.BigInteger, primary_key=True, autoincrement=True),
        sa.Column(
            "event_id", sa.Text, sa.ForeignKey("events.event_id"), nullable=False
        ),
        sa.Column("parser_kind", sa.Text, nullable=False),
        sa.Column("parser_version", sa.Text, nullable=False),
        sa.Column("schema_version", sa.Text, nullable=False),
        sa.Column("output_json", JSONB, nullable=False),
        sa.Column("validation_status", sa.Text, nullable=False),
        sa.Column("validation_errors", JSONB, nullable=True),
        sa.Column(
            "created_at_utc",
            sa.DateTime(timezone=True),
            nullable=False,
            server_default=sa.text("now()"),
        ),
    )

    op.create_table(
        "macro_series",
        sa.Column("series_id", sa.Text, primary_key=True),
        sa.Column("title", sa.Text, nullable=True),
        sa.Column("frequency", sa.Text, nullable=True),
        sa.Column("units", sa.Text, nullable=True),
        sa.Column("source_name", sa.Text, nullable=False),
        sa.Column("metadata_json", JSONB, nullable=False, server_default=sa.text("'{}'")),
        sa.Column(
            "created_at_utc",
            sa.DateTime(timezone=True),
            nullable=False,
            server_default=sa.text("now()"),
        ),
    )

    op.create_table(
        "macro_observations",
        sa.Column("id", sa.BigInteger, primary_key=True, autoincrement=True),
        sa.Column(
            "series_id",
            sa.Text,
            sa.ForeignKey("macro_series.series_id"),
            nullable=False,
        ),
        sa.Column("observation_date", sa.Date, nullable=False),
        sa.Column("value", sa.Numeric, nullable=True),
        sa.Column(
            "created_at_utc",
            sa.DateTime(timezone=True),
            nullable=False,
            server_default=sa.text("now()"),
        ),
        sa.UniqueConstraint(
            "series_id", "observation_date", name="uq_macro_obs_series_date"
        ),
    )

    op.create_table(
        "short_sale_daily",
        sa.Column("id", sa.BigInteger, primary_key=True, autoincrement=True),
        sa.Column(
            "symbol_id",
            sa.Text,
            sa.ForeignKey("symbol_master.symbol_id"),
            nullable=True,
        ),
        sa.Column("ticker_raw", sa.Text, nullable=False),
        sa.Column("trade_date", sa.Date, nullable=False),
        sa.Column("short_volume", sa.BigInteger, nullable=False),
        sa.Column("short_exempt_volume", sa.BigInteger, nullable=True),
        sa.Column("total_volume", sa.BigInteger, nullable=True),
        sa.Column("source_name", sa.Text, nullable=False),
        sa.Column(
            "created_at_utc",
            sa.DateTime(timezone=True),
            nullable=False,
            server_default=sa.text("now()"),
        ),
        sa.UniqueConstraint(
            "ticker_raw",
            "trade_date",
            "source_name",
            name="uq_short_sale_ticker_date_source",
        ),
    )
    op.create_index(
        "ix_short_sale_ticker_date", "short_sale_daily", ["ticker_raw", "trade_date"]
    )

    op.create_table(
        "feature_snapshots",
        sa.Column("feature_snapshot_id", sa.BigInteger, primary_key=True, autoincrement=True),
        sa.Column(
            "event_id", sa.Text, sa.ForeignKey("events.event_id"), nullable=False
        ),
        sa.Column("snapshot_name", sa.Text, nullable=False),
        sa.Column("snapshot_version", sa.Text, nullable=False),
        sa.Column("feature_json", JSONB, nullable=False),
        sa.Column(
            "created_at_utc",
            sa.DateTime(timezone=True),
            nullable=False,
            server_default=sa.text("now()"),
        ),
    )

    op.create_table(
        "order_plans",
        sa.Column("order_plan_id", sa.BigInteger, primary_key=True, autoincrement=True),
        sa.Column(
            "event_id", sa.Text, sa.ForeignKey("events.event_id"), nullable=False
        ),
        sa.Column(
            "symbol_id",
            sa.Text,
            sa.ForeignKey("symbol_master.symbol_id"),
            nullable=False,
        ),
        sa.Column("side", sa.Text, nullable=False),
        sa.Column("planned_entry_date", sa.Date, nullable=False),
        sa.Column("planned_order_type", sa.Text, nullable=False),
        sa.Column("planned_price", sa.Numeric, nullable=True),
        sa.Column("stop_price", sa.Numeric, nullable=True),
        sa.Column("take_profit_price", sa.Numeric, nullable=True),
        sa.Column("quantity_plan", sa.Numeric, nullable=True),
        sa.Column("status", sa.Text, nullable=False, server_default=sa.text("'draft'")),
        sa.Column(
            "created_at_utc",
            sa.DateTime(timezone=True),
            nullable=False,
            server_default=sa.text("now()"),
        ),
    )

    op.create_table(
        "sync_checkpoints",
        sa.Column("id", sa.BigInteger, primary_key=True, autoincrement=True),
        sa.Column("domain", sa.Text, nullable=False),
        sa.Column("last_sync_at_utc", sa.DateTime(timezone=True), nullable=True),
        sa.Column("last_sync_params", JSONB, nullable=False, server_default=sa.text("'{}'")),
        sa.Column("status", sa.Text, nullable=False),
        sa.Column(
            "created_at_utc",
            sa.DateTime(timezone=True),
            nullable=False,
            server_default=sa.text("now()"),
        ),
        sa.Column(
            "updated_at_utc",
            sa.DateTime(timezone=True),
            nullable=False,
            server_default=sa.text("now()"),
        ),
        sa.UniqueConstraint("domain", name="uq_sync_checkpoints_domain"),
    )


def downgrade() -> None:
    op.drop_table("sync_checkpoints")
    op.drop_table("order_plans")
    op.drop_table("feature_snapshots")
    op.drop_index("ix_short_sale_ticker_date", table_name="short_sale_daily")
    op.drop_table("short_sale_daily")
    op.drop_table("macro_observations")
    op.drop_table("macro_series")
    op.drop_table("event_parses")
    op.drop_index("ix_events_primary_document_id", table_name="events")
    op.drop_index("ix_events_event_type_date", table_name="events")
    op.drop_table("events")
    op.drop_table("exhibit_cache")
    op.drop_table("document_exhibits")
    op.drop_index("ix_documents_form_type_filing_date", table_name="documents")
    op.drop_index("ix_documents_issuer_filing_date", table_name="documents")
    op.drop_table("documents")
    op.drop_index("ix_job_runs_job_name_run_date", table_name="job_runs")
    op.drop_table("job_runs")
    op.drop_table("symbol_master")
    op.drop_table("issuer_master")
