"""Phase 5: scoring recency/severity columns and snapshot breakdown fields.

Revision ID: b030phase5
Revises: b029phase3
"""

from typing import Sequence, Union

import sqlalchemy as sa
from alembic import op
from sqlalchemy.dialects import postgresql

revision: str = "b030phase5"
down_revision: Union[str, None] = "b029phase3"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def _column_names(table: str) -> set[str]:
    bind = op.get_bind()
    insp = sa.inspect(bind)
    return {c["name"] for c in insp.get_columns(table)}


def upgrade() -> None:
    snap_cols = _column_names("coverage_snapshots")
    if "by_tactic" not in snap_cols:
        op.add_column(
            "coverage_snapshots",
            sa.Column("by_tactic", postgresql.JSONB(), nullable=False, server_default="{}"),
        )
    if "by_status" not in snap_cols:
        op.add_column(
            "coverage_snapshots",
            sa.Column("by_status", postgresql.JSONB(), nullable=False, server_default="{}"),
        )
    if "stale_count" not in snap_cols:
        op.add_column(
            "coverage_snapshots",
            sa.Column("stale_count", sa.Integer(), nullable=False, server_default="0"),
        )
    if "never_tested_count" not in snap_cols:
        op.add_column(
            "coverage_snapshots",
            sa.Column("never_tested_count", sa.Integer(), nullable=False, server_default="0"),
        )
    if "coverage_percentage" not in snap_cols:
        op.add_column(
            "coverage_snapshots",
            sa.Column("coverage_percentage", sa.Float(), nullable=False, server_default="0"),
        )

    cfg_cols = _column_names("scoring_config")
    if "weight_recency" not in cfg_cols and "weight_freshness" in cfg_cols:
        op.alter_column(
            "scoring_config",
            "weight_freshness",
            new_column_name="weight_recency",
        )
        cfg_cols.remove("weight_freshness")
        cfg_cols.add("weight_recency")
    elif "weight_recency" not in cfg_cols:
        op.add_column(
            "scoring_config",
            sa.Column("weight_recency", sa.Float(), nullable=False, server_default="10.0"),
        )

    if "weight_severity" not in cfg_cols and "weight_platform_diversity" in cfg_cols:
        op.alter_column(
            "scoring_config",
            "weight_platform_diversity",
            new_column_name="weight_severity",
        )
    elif "weight_severity" not in cfg_cols:
        op.add_column(
            "scoring_config",
            sa.Column("weight_severity", sa.Float(), nullable=False, server_default="10.0"),
        )

    if "updated_by" not in cfg_cols:
        op.add_column(
            "scoring_config",
            sa.Column(
                "updated_by",
                postgresql.UUID(as_uuid=True),
                sa.ForeignKey("users.id", ondelete="SET NULL"),
                nullable=True,
            ),
        )


def downgrade() -> None:
    cfg_cols = _column_names("scoring_config")
    if "updated_by" in cfg_cols:
        op.drop_column("scoring_config", "updated_by")
    if "weight_severity" in cfg_cols:
        op.alter_column(
            "scoring_config",
            "weight_severity",
            new_column_name="weight_platform_diversity",
        )
    if "weight_recency" in cfg_cols:
        op.alter_column(
            "scoring_config",
            "weight_recency",
            new_column_name="weight_freshness",
        )

    for col in (
        "coverage_percentage",
        "never_tested_count",
        "stale_count",
        "by_status",
        "by_tactic",
    ):
        if col in _column_names("coverage_snapshots"):
            op.drop_column("coverage_snapshots", col)
