"""ml_settings crop-proposer / detector config (#134)

Move the WHERE-to-crop detector config (per-proposer enable + weights + conf,
plus caps + dedupe IoU) into the DB so it's UI-tunable and announced to the GPU
agent in the lease (like the embedder model) — no restart, agent env is now
bootstrap-only. All server_defaults are the working values so existing rows +
fresh installs crop out-of-the-box with all three proposers ON.

Revision ID: 0078
Revises: 0077
Create Date: 2026-07-05
"""
from typing import Sequence, Union

import sqlalchemy as sa
from alembic import op

revision: str = "0078"
down_revision: Union[str, None] = "0077"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


_ANATOMY_DEFAULT = (
    "https://github.com/aperveyev/booru_yolo/raw/main/models/yolov11m_aa22.pt"
)
_PANEL_DEFAULT = "mosesb/best-comic-panel-detection::best.pt"


def upgrade() -> None:
    op.add_column("ml_settings", sa.Column(
        "detector_person_enabled", sa.Boolean(), nullable=False,
        server_default=sa.true()))
    op.add_column("ml_settings", sa.Column(
        "detector_person_weights", sa.String(512), nullable=False,
        server_default="yolo11n.pt"))
    op.add_column("ml_settings", sa.Column(
        "detector_person_conf", sa.Float(), nullable=False,
        server_default=sa.text("0.35")))
    op.add_column("ml_settings", sa.Column(
        "detector_anatomy_enabled", sa.Boolean(), nullable=False,
        server_default=sa.true()))
    op.add_column("ml_settings", sa.Column(
        "detector_anatomy_weights", sa.String(512), nullable=False,
        server_default=_ANATOMY_DEFAULT))
    op.add_column("ml_settings", sa.Column(
        "detector_anatomy_conf", sa.Float(), nullable=False,
        server_default=sa.text("0.30")))
    op.add_column("ml_settings", sa.Column(
        "detector_panel_enabled", sa.Boolean(), nullable=False,
        server_default=sa.true()))
    op.add_column("ml_settings", sa.Column(
        "detector_panel_weights", sa.String(512), nullable=False,
        server_default=_PANEL_DEFAULT))
    op.add_column("ml_settings", sa.Column(
        "detector_panel_conf", sa.Float(), nullable=False,
        server_default=sa.text("0.30")))
    op.add_column("ml_settings", sa.Column(
        "detector_max_figures", sa.Integer(), nullable=False,
        server_default=sa.text("8")))
    op.add_column("ml_settings", sa.Column(
        "detector_max_components", sa.Integer(), nullable=False,
        server_default=sa.text("8")))
    op.add_column("ml_settings", sa.Column(
        "detector_max_panels", sa.Integer(), nullable=False,
        server_default=sa.text("8")))
    op.add_column("ml_settings", sa.Column(
        "detector_max_regions", sa.Integer(), nullable=False,
        server_default=sa.text("128")))
    op.add_column("ml_settings", sa.Column(
        "detector_dedupe_iou", sa.Float(), nullable=False,
        server_default=sa.text("0.85")))


def downgrade() -> None:
    for col in (
        "detector_person_enabled", "detector_person_weights", "detector_person_conf",
        "detector_anatomy_enabled", "detector_anatomy_weights", "detector_anatomy_conf",
        "detector_panel_enabled", "detector_panel_weights", "detector_panel_conf",
        "detector_max_figures", "detector_max_components", "detector_max_panels",
        "detector_max_regions", "detector_dedupe_iou",
    ):
        op.drop_column("ml_settings", col)
