"""fc2a: tag kinds, import_task, import_batch, integrity_status

Revision ID: 0002
Revises: 0001
Create Date: 2026-05-14

"""
from typing import Sequence, Union

import sqlalchemy as sa
from alembic import op

revision: str = "0002"
down_revision: Union[str, None] = "0001"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None

TAG_KINDS = (
    "artist",
    "character",
    "fandom",
    "general",
    "series",
    "archive",
    "post",
    "meta",
    "rating",
)


def upgrade() -> None:
    # --- Tag kind enum + fandom_id ---
    tag_kind = sa.Enum(*TAG_KINDS, name="tag_kind")
    tag_kind.create(op.get_bind(), checkfirst=True)

    op.add_column(
        "tag",
        sa.Column("kind", tag_kind, nullable=False, server_default="general"),
    )
    op.add_column(
        "tag",
        sa.Column("fandom_id", sa.Integer(), nullable=True),
    )
    op.create_foreign_key(
        "fk_tag_fandom_id_tag",
        "tag",
        "tag",
        ["fandom_id"],
        ["id"],
        ondelete="SET NULL",
    )

    # Drop the old global uniqueness on name; add kind+fandom-aware uniqueness.
    op.drop_constraint("uq_tag_name", "tag", type_="unique")
    op.drop_index("ix_tag_name", table_name="tag")
    op.execute(
        """
        CREATE UNIQUE INDEX uq_tag_name_kind_fandom
          ON tag (name, kind, COALESCE(fandom_id, 0))
        """
    )

    # CHECK: fandom_id is only allowed for character kind.
    op.create_check_constraint(
        "ck_tag_fandom_requires_character",
        "tag",
        "(fandom_id IS NULL) OR (kind = 'character')",
    )

    # Drop the old namespace column — superseded by kind.
    op.drop_index("ix_tag_namespace", table_name="tag")
    op.drop_column("tag", "namespace")

    # --- ImportBatch ---
    op.create_table(
        "import_batch",
        sa.Column("id", sa.Integer(), nullable=False),
        sa.Column("triggered_by", sa.String(length=32), nullable=False),
        sa.Column("source_path", sa.Text(), nullable=False),
        sa.Column("scan_mode", sa.String(length=16), nullable=False),
        sa.Column(
            "started_at",
            sa.DateTime(timezone=True),
            nullable=False,
            server_default=sa.func.now(),
        ),
        sa.Column("finished_at", sa.DateTime(timezone=True), nullable=True),
        sa.Column("total_files", sa.Integer(), nullable=False, server_default="0"),
        sa.Column("imported", sa.Integer(), nullable=False, server_default="0"),
        sa.Column("skipped", sa.Integer(), nullable=False, server_default="0"),
        sa.Column("failed", sa.Integer(), nullable=False, server_default="0"),
        sa.Column("status", sa.String(length=16), nullable=False, server_default="running"),
        sa.PrimaryKeyConstraint("id", name="pk_import_batch"),
    )
    op.create_index("ix_import_batch_status", "import_batch", ["status"])

    # --- ImportTask ---
    op.create_table(
        "import_task",
        sa.Column("id", sa.Integer(), nullable=False),
        sa.Column("batch_id", sa.Integer(), nullable=False),
        sa.Column("source_path", sa.Text(), nullable=False),
        sa.Column("task_type", sa.String(length=16), nullable=False),
        sa.Column("status", sa.String(length=16), nullable=False, server_default="pending"),
        sa.Column("result_image_id", sa.Integer(), nullable=True),
        sa.Column("error", sa.Text(), nullable=True),
        sa.Column("size_bytes", sa.BigInteger(), nullable=True),
        sa.Column(
            "created_at",
            sa.DateTime(timezone=True),
            nullable=False,
            server_default=sa.func.now(),
        ),
        sa.Column("started_at", sa.DateTime(timezone=True), nullable=True),
        sa.Column("finished_at", sa.DateTime(timezone=True), nullable=True),
        sa.ForeignKeyConstraint(
            ["batch_id"],
            ["import_batch.id"],
            name="fk_import_task_batch_id_import_batch",
            ondelete="CASCADE",
        ),
        sa.ForeignKeyConstraint(
            ["result_image_id"],
            ["image_record.id"],
            name="fk_import_task_result_image_id_image_record",
            ondelete="SET NULL",
        ),
        sa.PrimaryKeyConstraint("id", name="pk_import_task"),
    )
    op.create_index("ix_import_task_batch_id", "import_task", ["batch_id"])
    op.create_index("ix_import_task_status", "import_task", ["status"])
    op.create_index(
        "ix_import_task_created_at_desc",
        "import_task",
        [sa.text("created_at DESC")],
    )

    # --- ImportSettings (single-row table) ---
    op.create_table(
        "import_settings",
        sa.Column("id", sa.Integer(), nullable=False),
        sa.Column("import_scan_path", sa.Text(), nullable=False, server_default="/import"),
        sa.Column("min_width", sa.Integer(), nullable=False, server_default="0"),
        sa.Column("min_height", sa.Integer(), nullable=False, server_default="0"),
        sa.Column(
            "skip_transparent", sa.Boolean(), nullable=False, server_default=sa.false()
        ),
        sa.Column(
            "transparency_threshold",
            sa.Float(),
            nullable=False,
            server_default="0.9",
        ),
        sa.Column(
            "skip_single_color", sa.Boolean(), nullable=False, server_default=sa.false()
        ),
        sa.Column(
            "single_color_threshold",
            sa.Float(),
            nullable=False,
            server_default="0.95",
        ),
        sa.Column("single_color_tolerance", sa.Integer(), nullable=False, server_default="30"),
        sa.PrimaryKeyConstraint("id", name="pk_import_settings"),
        sa.CheckConstraint("id = 1", name="ck_import_settings_singleton"),
    )
    # Seed the single row immediately so callers can always SELECT id=1.
    op.execute("INSERT INTO import_settings (id) VALUES (1)")

    # --- ImageRecord additions ---
    op.add_column(
        "image_record",
        sa.Column(
            "integrity_status",
            sa.String(length=24),
            nullable=False,
            server_default="unknown",
        ),
    )
    op.create_index(
        "ix_image_record_integrity_status",
        "image_record",
        ["integrity_status"],
    )


def downgrade() -> None:
    op.drop_index("ix_image_record_integrity_status", table_name="image_record")
    op.drop_column("image_record", "integrity_status")

    op.drop_table("import_settings")
    op.drop_index("ix_import_task_created_at_desc", table_name="import_task")
    op.drop_index("ix_import_task_status", table_name="import_task")
    op.drop_index("ix_import_task_batch_id", table_name="import_task")
    op.drop_table("import_task")
    op.drop_index("ix_import_batch_status", table_name="import_batch")
    op.drop_table("import_batch")

    op.drop_constraint("ck_tag_fandom_requires_character", "tag", type_="check")
    op.execute("DROP INDEX uq_tag_name_kind_fandom")
    op.add_column("tag", sa.Column("namespace", sa.String(length=64), nullable=True))
    op.create_index("ix_tag_namespace", "tag", ["namespace"])
    op.create_index("ix_tag_name", "tag", ["name"], unique=False)
    op.create_unique_constraint("uq_tag_name", "tag", ["name"])
    op.drop_constraint("fk_tag_fandom_id_tag", "tag", type_="foreignkey")
    op.drop_column("tag", "fandom_id")
    op.drop_column("tag", "kind")
    sa.Enum(name="tag_kind").drop(op.get_bind(), checkfirst=True)
