"""Resolver tagów. Tag identyfikuje slug (case-insensitive)."""
from __future__ import annotations

import uuid

from sqlalchemy import select
from sqlalchemy.dialects.postgresql import insert as pg_insert
from sqlalchemy.orm import Session

from app.models.tag import Tag
from app.normalize.scenes import NormalizedTag
from app.normalize.text import slugify


def _canonical_dup2_slug(session: Session, slug: str) -> str:
    """Kanonizuje numbered-duplicate slug `<base>2` → `<base>`.

    TPDB taxonomy emituje zduplikowane tagi z suffixem `2` (name "Bubble Butt2").
    `slugify` daje `bubble-butt2` (bez separatora przed cyfrą) → bez tego osobny tag
    obok `bubble-butt` z tysiącami scen (dup-tag bug 2026-06-06; backfill
    scripts/merge_dup2_tags.py). Gdy slug kończy się literą+"2" i baza istnieje jako
    tag, używamy bazy. Warunek `[-2].isalpha()` wyklucza legit sufiksy gdzie cyfra jest
    znacząca (milf-30, teen18 — nie kończą się "2"; chroni też przed "...22")."""
    if len(slug) > 1 and slug[-1] == "2" and slug[-2].isalpha():
        base = slug[:-1]
        if session.execute(select(Tag.id).where(Tag.slug == base)).first():
            return base
    return slug


def resolve_tag(session: Session, *, norm: NormalizedTag) -> Tag | None:
    slug = norm.slug or slugify(norm.name)
    # DB columns: name VARCHAR(128), slug VARCHAR(128). Scraper occasionally
    # captures multi-tag composite URLs (e.g. /tags/face-sitting-fake-tits-...)
    # which break the insert. Reject anything >120 chars instead of crashing
    # the whole ingest batch.
    if len(slug) > 120:
        return None
    slug = _canonical_dup2_slug(session, slug)
    tag = session.execute(select(Tag).where(Tag.slug == slug)).scalar_one_or_none()
    if tag is not None:
        return tag

    name = (norm.name or "").strip() or slug.replace("-", " ").title()
    if len(name) > 120:
        name = name[:120]
    # Concurrent insert race: worker scraper + API enrich_tags_from_tube oba
    # robią lookup→insert na tym samym slug ('hardcore-sex'), oba widzą NULL,
    # oba próbują INSERT, drugi pada UniqueViolation uq_tags_slug (Sentry GOON-H,
    # 5 events od 2026-05-12). ON CONFLICT DO NOTHING + re-SELECT po slug
    # załatwia atomowo — Postgres serializuje na unique index.
    stmt = (
        pg_insert(Tag.__table__)
        .values(name=name, slug=slug)
        .on_conflict_do_nothing(index_elements=["slug"])
    )
    session.execute(stmt)
    return session.execute(select(Tag).where(Tag.slug == slug)).scalar_one_or_none()


def resolve_tag_by_id(session: Session, tag_id: uuid.UUID) -> Tag | None:
    return session.get(Tag, tag_id)
