"""Title-based WIP auto-tagging (task #1458) — integration tests for the apply
helpers and the operator-triggered backfill sweep against a real DB. The
importer's live hook is a thin call to these same tested pieces (matcher +
apply), so the DB-facing behaviour is covered here.
"""
import pytest
from sqlalchemy import select

from backend.app.celery_app import celery
from backend.app.models import Artist, ImageProvenance, ImageRecord, Post, Source
from backend.app.models.tag import image_tag
from backend.app.services.wip_title import (
    WIP_TITLE_SOFT_SOURCE,
    apply_wip_image_tags,
    resolve_wip_tag_id,
)

pytestmark = pytest.mark.integration

_N = 0


@pytest.fixture(autouse=True)
def eager():
    celery.conf.task_always_eager = True
    yield
    celery.conf.task_always_eager = False


def _img(db_sync):
    global _N
    _N += 1
    rec = ImageRecord(
        path=f"/images/w/{_N}.jpg", sha256=f"w{_N:063d}",
        size_bytes=1, mime="image/jpeg", width=1, height=1,
        origin="imported_filesystem", integrity_status="unknown",
    )
    db_sync.add(rec)
    db_sync.flush()
    return rec


def _post(db_sync, *, title, slug, ext):
    a = Artist(name=slug.upper(), slug=slug)
    db_sync.add(a)
    db_sync.flush()
    s = Source(artist_id=a.id, platform="patreon", url=f"https://patreon.test/{slug}")
    db_sync.add(s)
    db_sync.flush()
    p = Post(source_id=s.id, artist_id=a.id, external_post_id=ext, post_title=title)
    db_sync.add(p)
    db_sync.flush()
    return s, p


def _link(db_sync, rec, post, source):
    db_sync.add(ImageProvenance(
        image_record_id=rec.id, post_id=post.id, source_id=source.id,
    ))
    db_sync.flush()


def _wip_source(db_sync, image_id, tag_id):
    return db_sync.execute(
        select(image_tag.c.source).where(
            image_tag.c.image_record_id == image_id,
            image_tag.c.tag_id == tag_id,
        )
    ).scalar_one_or_none()


def test_resolve_wip_tag_id_present(db_sync):
    # The `wip` system tag is seeded by migration 0075 and restored between tests.
    assert resolve_wip_tag_id(db_sync) is not None


def test_apply_is_idempotent_and_stamps_source(db_sync):
    tag_id = resolve_wip_tag_id(db_sync)
    rec = _img(db_sync)
    db_sync.commit()

    assert apply_wip_image_tags(db_sync, [rec.id], tag_id) == 1
    # Second apply is a no-op (ON CONFLICT DO NOTHING) — never disturbs the row.
    assert apply_wip_image_tags(db_sync, [rec.id], tag_id) == 0
    assert _wip_source(db_sync, rec.id, tag_id) == "wip_title"


def test_backfill_tags_only_wip_titled_posts(db_sync):
    from backend.app.tasks.maintenance import backfill_wip_title_tags

    tag_id = resolve_wip_tag_id(db_sync)
    wip_rec = _img(db_sync)
    plain_rec = _img(db_sync)
    swipe_rec = _img(db_sync)
    s1, wip_post = _post(db_sync, title="Cool piece - WIP Part 1", slug="wipy", ext="1")
    s2, plain_post = _post(db_sync, title="Finished commission", slug="doney", ext="2")
    s3, swipe_post = _post(db_sync, title="a quick swipe", slug="swipey", ext="3")
    _link(db_sync, wip_rec, wip_post, s1)
    _link(db_sync, plain_rec, plain_post, s2)
    _link(db_sync, swipe_rec, swipe_post, s3)   # 'swipe' must NOT trip the matcher
    db_sync.commit()

    assert backfill_wip_title_tags.apply().get() == 1

    assert _wip_source(db_sync, wip_rec.id, tag_id) == "wip_title"
    assert _wip_source(db_sync, plain_rec.id, tag_id) is None
    assert _wip_source(db_sync, swipe_rec.id, tag_id) is None

    # Idempotent: a second sweep finds the tag already present and applies nothing.
    assert backfill_wip_title_tags.apply().get() == 0


def test_apply_soft_source_stamps_wip_title_soft(db_sync):
    # The soft tier (#1474) stamps a distinct provisional source.
    tag_id = resolve_wip_tag_id(db_sync)
    rec = _img(db_sync)
    db_sync.commit()
    assert apply_wip_image_tags(
        db_sync, [rec.id], tag_id, source=WIP_TITLE_SOFT_SOURCE
    ) == 1
    assert _wip_source(db_sync, rec.id, tag_id) == "wip_title_soft"
