"""add-tracker-stats

Revision ID: e8b6da638a6f
Revises: 8d38682c9b50
Create Date: 2025-03-13 08:10:14.441300+00:00

"""

from datetime import UTC, datetime
from typing import Sequence, Union

import sqlalchemy as sa
import sqlmodel.sql.sqltypes
from alembic import op

from sciop import models

# revision identifiers, used by Alembic.
revision: str = "e8b6da638a6f"
down_revision: Union[str, None] = "8d38682c9b50"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    Tracker = op.create_table(
        "trackers",
        sa.Column("created_at", sa.DateTime(), nullable=True),
        sa.Column("updated_at", sa.DateTime(), nullable=True),
        sa.Column("announce_url", sqlmodel.sql.sqltypes.AutoString(length=512), nullable=False),
        sa.Column(
            "protocol", sa.Enum("udp", "http", "https", name="trackerprotocol"), nullable=False
        ),
        sa.Column("tracker_id", sa.Integer(), nullable=False),
        sa.Column("last_scraped_at", sa.DateTime(), nullable=True),
        sa.Column("n_errors", sa.Integer(), nullable=False),
        sa.Column(
            "error_type",
            sa.Enum("dns", "connection", "timeout", "unpack", "default", name="scrapeerrortype"),
            nullable=True,
        ),
        sa.Column("next_scrape_after", sa.DateTime(), nullable=True),
        sa.PrimaryKeyConstraint("tracker_id", name=op.f("pk_trackers_tracker_id")),
    )
    with op.batch_alter_table("trackers", schema=None) as batch_op:
        batch_op.create_index(batch_op.f("ix_trackers_announce_url"), ["announce_url"], unique=True)

    TorrentTrackerLinks = op.create_table(
        "torrent_tracker_links",
        sa.Column("created_at", sa.DateTime(), nullable=True),
        sa.Column("updated_at", sa.DateTime(), nullable=True),
        sa.Column("torrent_file_id", sa.Integer(), nullable=False),
        sa.Column("tracker_id", sa.Integer(), nullable=False),
        sa.Column("seeders", sa.Integer(), nullable=True),
        sa.Column("leechers", sa.Integer(), nullable=True),
        sa.Column("completed", sa.Integer(), nullable=True),
        sa.Column("last_scraped_at", sa.DateTime(), nullable=True),
        sa.ForeignKeyConstraint(
            ["torrent_file_id"],
            ["torrent_files.torrent_file_id"],
            name=op.f("fk_torrent_tracker_links_torrent_file_id_torrent_files"),
            ondelete="CASCADE",
        ),
        sa.ForeignKeyConstraint(
            ["tracker_id"],
            ["trackers.tracker_id"],
            name=op.f("fk_torrent_tracker_links_tracker_id_trackers"),
        ),
        sa.PrimaryKeyConstraint(
            "torrent_file_id",
            "tracker_id",
            name=op.f("pk_torrent_tracker_links_torrent_file_id_tracker_id"),
        ),
        sa.UniqueConstraint(
            "torrent_file_id",
            "tracker_id",
            name=op.f("uq_torrent_tracker_links_torrent_file_id_tracker_id"),
        ),
    )

    with op.batch_alter_table("uploads", schema=None) as batch_op:
        batch_op.drop_column("seeders")
        batch_op.drop_column("leechers")

    # ### end Alembic commands ###

    # move trackers
    conn = op.get_bind()
    tracker_res = conn.execute(sa.text("SELECT torrent_id, url FROM trackers_in_torrent"))
    trackers = tracker_res.fetchall()
    tracker_urls = list(set([t[1] for t in trackers]))
    tracker_ids = list(range(1, len(trackers) + 1))
    url_to_id = {url: t_id for url, t_id in zip(tracker_urls, tracker_ids)}
    now = datetime.now(UTC)
    op.bulk_insert(
        Tracker,
        [
            {
                "tracker_id": t_id,
                "announce_url": t_url,
                "created_at": now,
                "updated_at": now,
                "protocol": t_url.split("://")[0],
                "n_errors": 0,
            }
            for t_id, t_url in zip(tracker_ids, tracker_urls)
        ],
    )
    op.bulk_insert(
        TorrentTrackerLinks,
        [
            {
                "tracker_id": url_to_id[t[1]],
                "torrent_file_id": t[0],
                "created_at": now,
                "updated_at": now,
            }
            for t in trackers
        ],
    )

    op.drop_table("trackers_in_torrent")

    # create search tables for upload
    models.Upload.after_create(models.Upload.__table__, conn)


def downgrade() -> None:
    # ### commands auto generated by Alembic - please adjust! ###
    with op.batch_alter_table("uploads", schema=None) as batch_op:
        batch_op.add_column(sa.Column("leechers", sa.INTEGER(), nullable=True))
        batch_op.add_column(sa.Column("seeders", sa.INTEGER(), nullable=True))

    TrackerInTorrent = op.create_table(
        "trackers_in_torrent",
        sa.Column("created_at", sa.DATETIME(), nullable=True),
        sa.Column("updated_at", sa.DATETIME(), nullable=True),
        sa.Column("tracker_in_torrent_id", sa.INTEGER(), nullable=False),
        sa.Column("url", sa.VARCHAR(length=512), nullable=False),
        sa.Column("torrent_id", sa.INTEGER(), nullable=True),
        sa.ForeignKeyConstraint(
            ["torrent_id"],
            ["torrent_files.torrent_file_id"],
            name="fk_trackers_in_torrent_torrent_id_torrent_files",
            ondelete="CASCADE",
        ),
        sa.PrimaryKeyConstraint(
            "tracker_in_torrent_id", name="pk_trackers_in_torrent_tracker_in_torrent_id"
        ),
    )

    conn = op.get_bind()
    tracker_res = conn.execute(
        sa.text(
            """
        SELECT 
          torrent_tracker_links.torrent_file_id, 
          trackers.announce_url, 
          torrent_tracker_links.created_at, 
          torrent_tracker_links.updated_at 
        FROM torrent_tracker_links
        INNER JOIN trackers ON torrent_tracker_links.tracker_id = trackers.tracker_id
        """
        )
    )
    trackers = tracker_res.fetchall()
    op.bulk_insert(
        TrackerInTorrent,
        [
            {
                "torrent_id": t[0],
                "url": t[1],
                "created_at": t[3],
                "updated_at": t[2],
            }
            for t in trackers
        ],
    )

    op.drop_table("torrent_tracker_links")
    with op.batch_alter_table("trackers", schema=None) as batch_op:
        batch_op.drop_index(batch_op.f("ix_trackers_announce_url"))

    op.drop_table("trackers")
    # ### end Alembic commands ###
