"""FC-6.x — cosmetic chapter dividers over the flat series page run."""

import pytest
from sqlalchemy import func, select

from backend.app.models import ImageRecord, TagKind
from backend.app.models.series_chapter import SeriesChapter
from backend.app.models.series_page import SeriesPage
from backend.app.services.series_service import SeriesError, SeriesService
from backend.app.services.tag_service import TagService

pytestmark = pytest.mark.integration

_SEQ = 0


async def _img(db):
    global _SEQ
    _SEQ += 1
    rec = ImageRecord(
        path=f"/tmp/fc_sc_{_SEQ}.png", sha256=f"{_SEQ:064d}",
        size_bytes=1, mime="image/png", origin="uploaded",
    )
    db.add(rec)
    await db.flush()
    return rec.id


async def _series(db, name):
    return (await TagService(db).find_or_create(name, TagKind.series)).id


async def _order(db, sid):
    rows = (
        await db.execute(
            select(SeriesPage.image_id)
            .where(SeriesPage.series_tag_id == sid)
            .order_by(SeriesPage.page_number)
        )
    ).scalars().all()
    return list(rows)


async def _dividers(db, sid):
    """(anchor_image_id, title, stated_part) ordered by anchor page position."""
    rows = (
        await db.execute(
            select(
                SeriesChapter.id,
                SeriesPage.image_id,
                SeriesChapter.title,
                SeriesChapter.stated_part,
            )
            .join(SeriesPage, SeriesPage.id == SeriesChapter.anchor_page_id)
            .where(SeriesChapter.series_tag_id == sid)
            .order_by(SeriesPage.page_number)
        )
    ).all()
    return rows


@pytest.mark.asyncio
async def test_create_divider_anchors_before_a_page(db):
    svc = SeriesService(db)
    sid = await _series(db, "C1")
    i1, i2, i3 = await _img(db), await _img(db), await _img(db)
    await svc.add_images(sid, [i1, i2, i3])
    await svc.create_divider(sid, i2, title="Two", stated_part=2)
    divs = await _dividers(db, sid)
    assert len(divs) == 1
    assert divs[0].image_id == i2
    assert divs[0].title == "Two"
    assert divs[0].stated_part == 2


@pytest.mark.asyncio
async def test_create_divider_rejects_image_not_in_series(db):
    svc = SeriesService(db)
    sid = await _series(db, "C2")
    i1 = await _img(db)
    await svc.add_images(sid, [i1])
    with pytest.raises(SeriesError):
        await svc.create_divider(sid, 999999)


@pytest.mark.asyncio
async def test_one_divider_per_page(db):
    svc = SeriesService(db)
    sid = await _series(db, "C3")
    i1, i2 = await _img(db), await _img(db)
    await svc.add_images(sid, [i1, i2])
    await svc.create_divider(sid, i2)
    with pytest.raises(SeriesError):
        await svc.create_divider(sid, i2)


@pytest.mark.asyncio
async def test_update_divider_sets_part_title_and_moves_anchor(db):
    svc = SeriesService(db)
    sid = await _series(db, "C4")
    i1, i2, i3 = await _img(db), await _img(db), await _img(db)
    await svc.add_images(sid, [i1, i2, i3])
    d = await svc.create_divider(sid, i2)
    await svc.update_divider(
        sid, d["id"], set_title=True, title="X", set_part=True, stated_part=3
    )
    await svc.update_divider(
        sid, d["id"], set_anchor=True, anchor_image_id=i3
    )
    divs = await _dividers(db, sid)
    assert divs[0].image_id == i3
    assert divs[0].title == "X"
    assert divs[0].stated_part == 3


@pytest.mark.asyncio
async def test_delete_divider_leaves_pages(db):
    svc = SeriesService(db)
    sid = await _series(db, "C5")
    i1, i2, i3 = await _img(db), await _img(db), await _img(db)
    await svc.add_images(sid, [i1, i2, i3])
    d = await svc.create_divider(sid, i2)
    await svc.delete_divider(sid, d["id"])
    assert await _order(db, sid) == [i1, i2, i3]
    assert len(await _dividers(db, sid)) == 0


@pytest.mark.asyncio
async def test_removing_anchor_page_cascades_its_divider(db):
    svc = SeriesService(db)
    sid = await _series(db, "C6")
    i1, i2, i3 = await _img(db), await _img(db), await _img(db)
    await svc.add_images(sid, [i1, i2, i3])
    await svc.create_divider(sid, i2)
    await svc.remove_images(sid, [i2])
    # the divider anchored at i2 cascaded away; pages compacted to 1..N.
    assert len(await _dividers(db, sid)) == 0
    assert await _order(db, sid) == [i1, i3]
    cnt = await db.scalar(
        select(func.count()).select_from(SeriesChapter)
        .where(SeriesChapter.series_tag_id == sid)
    )
    assert cnt == 0


@pytest.mark.asyncio
async def test_list_pages_returns_dividers_and_part_gaps(db):
    svc = SeriesService(db)
    sid = await _series(db, "C7")
    i1, i2, i3 = await _img(db), await _img(db), await _img(db)
    await svc.add_images(sid, [i1, i2, i3])
    await svc.create_divider(sid, i1, stated_part=1)
    await svc.create_divider(sid, i3, stated_part=3)
    out = await svc.list_pages(sid)
    assert len(out["dividers"]) == 2
    assert len(out["part_gaps"]) == 1
    assert out["part_gaps"][0]["start"] == 2
    assert out["part_gaps"][0]["end"] == 2


@pytest.mark.asyncio
async def test_add_with_stated_pages_records_them(db):
    svc = SeriesService(db)
    sid = await _series(db, "C8")
    i1, i2 = await _img(db), await _img(db)
    await svc.add_images(sid, [i1, i2], stated_pages={i1: 9, i2: 10})
    rows = dict(
        (
            await db.execute(
                select(SeriesPage.image_id, SeriesPage.stated_page)
                .where(SeriesPage.series_tag_id == sid)
            )
        ).all()
    )
    assert rows[i1] == 9
    assert rows[i2] == 10
