import pytest

from backend.app.models import ImagePrediction, ImageRecord, TagAllowlist, TagKind
from backend.app.services.tag_service import TagService

pytestmark = pytest.mark.integration


@pytest.mark.asyncio
async def test_list_and_patch_and_delete(client, db):
    tag = await TagService(db).find_or_create("AL", TagKind.character)
    db.add(TagAllowlist(tag_id=tag.id, min_confidence=0.95))
    await db.commit()

    resp = await client.get("/api/allowlist")
    assert resp.status_code == 200
    assert any(r["tag_id"] == tag.id for r in await resp.get_json())

    resp = await client.patch(
        f"/api/tags/{tag.id}/allowlist", json={"min_confidence": 0.80}
    )
    assert resp.status_code == 204

    resp = await client.get(f"/api/tags/{tag.id}/allowlist")
    assert (await resp.get_json())["min_confidence"] == pytest.approx(0.80)

    resp = await client.delete(f"/api/tags/{tag.id}/allowlist")
    assert resp.status_code == 204
    resp = await client.get(f"/api/tags/{tag.id}/allowlist")
    assert resp.status_code == 404


@pytest.mark.asyncio
async def test_patch_rejects_out_of_range(client, db):
    tag = await TagService(db).find_or_create("AL2", TagKind.character)
    db.add(TagAllowlist(tag_id=tag.id))
    await db.commit()
    resp = await client.patch(
        f"/api/tags/{tag.id}/allowlist", json={"min_confidence": 1.5}
    )
    assert resp.status_code == 400


@pytest.mark.asyncio
async def test_coverage_endpoint(client, db):
    tag = await TagService(db).find_or_create("Cover", TagKind.general)
    db.add(TagAllowlist(tag_id=tag.id, min_confidence=0.90))
    for i, score in enumerate((0.95, 0.60)):
        img = ImageRecord(
            path=f"/images/cov{i}.jpg", sha256=f"cv{i:062d}", size_bytes=1,
            mime="image/jpeg", width=1, height=1,
            origin="imported_filesystem", integrity_status="unknown",
        )
        db.add(img)
        await db.flush()
        db.add(ImagePrediction(
            image_record_id=img.id, raw_name="Cover",
            category="general", score=score,
        ))
    await db.commit()

    # Explicit threshold.
    resp = await client.get(
        f"/api/tags/{tag.id}/allowlist/coverage?threshold=0.90"
    )
    assert resp.status_code == 200
    assert (await resp.get_json())["count"] == 1
    # Lower what-if threshold widens coverage.
    resp = await client.get(
        f"/api/tags/{tag.id}/allowlist/coverage?threshold=0.50"
    )
    assert (await resp.get_json())["count"] == 2
    # No threshold → uses the stored min_confidence (0.90).
    resp = await client.get(f"/api/tags/{tag.id}/allowlist/coverage")
    body = await resp.get_json()
    assert body["count"] == 1
    assert body["threshold"] == pytest.approx(0.90)


@pytest.mark.asyncio
async def test_coverage_rejects_bad_threshold(client, db):
    tag = await TagService(db).find_or_create("Cover2", TagKind.general)
    db.add(TagAllowlist(tag_id=tag.id))
    await db.commit()
    resp = await client.get(
        f"/api/tags/{tag.id}/allowlist/coverage?threshold=2.0"
    )
    assert resp.status_code == 400
