"""pixiv_seen_media + pixiv_failed_media: per-source ledgers

Revision ID: 0076
Revises: 0075
Create Date: 2026-07-03

Pixiv native ingester (milestone #129, gallery-dl → native-core migration).
Mirrors the Patreon (0037/0038) and SubscribeStar (0054) ledger tables: a
seen-ledger so routine walks skip already-ingested media (recovery bypasses
it) and a dead-letter ledger so persistently-failing media stops re-burning
backfill chunks. Pixiv URLs carry no content hash, so `filehash` is always the
synthesized ``<illust_id>:p<num>`` / ``<illust_id>:ugoira`` key — String(128)
matches the siblings. UNIQUE (source_id, filehash) is the upsert key on each.
"""
from typing import Sequence, Union

import sqlalchemy as sa
from alembic import op

revision: str = "0076"
down_revision: Union[str, None] = "0075"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
    op.create_table(
        "pixiv_seen_media",
        sa.Column("id", sa.Integer, primary_key=True),
        sa.Column(
            "source_id",
            sa.Integer,
            sa.ForeignKey("source.id", ondelete="CASCADE"),
            nullable=False,
            index=True,
        ),
        sa.Column("filehash", sa.String(128), nullable=False),
        sa.Column("post_id", sa.String(64), nullable=True),
        sa.Column(
            "seen_at",
            sa.DateTime(timezone=True),
            nullable=False,
            server_default=sa.text("NOW()"),
        ),
        sa.UniqueConstraint(
            "source_id", "filehash", name="uq_pixiv_seen_media_source_id"
        ),
    )
    op.create_table(
        "pixiv_failed_media",
        sa.Column("id", sa.Integer, primary_key=True),
        sa.Column(
            "source_id",
            sa.Integer,
            sa.ForeignKey("source.id", ondelete="CASCADE"),
            nullable=False,
            index=True,
        ),
        sa.Column("filehash", sa.String(128), nullable=False),
        sa.Column("attempts", sa.Integer, nullable=False, server_default="1"),
        sa.Column("last_error", sa.Text, nullable=True),
        sa.Column(
            "first_failed_at",
            sa.DateTime(timezone=True),
            nullable=False,
            server_default=sa.text("NOW()"),
        ),
        sa.Column(
            "last_failed_at",
            sa.DateTime(timezone=True),
            nullable=False,
            server_default=sa.text("NOW()"),
        ),
        sa.UniqueConstraint(
            "source_id", "filehash", name="uq_pixiv_failed_media_source_id"
        ),
    )


def downgrade() -> None:
    op.drop_table("pixiv_failed_media")
    op.drop_table("pixiv_seen_media")
