"""test_audiobook_catalog."""

from __future__ import annotations

import pytest
from sqlalchemy import create_engine, select
from sqlalchemy.orm import sessionmaker

from python.orm.richie import AudiobookAuthor, AudiobookSeries, RichieBase
from python.tools.audiobook import catalog


@pytest.fixture
def audiobook_session():
    engine = create_engine("sqlite+pysqlite:///:memory:", future=True)
    RichieBase.metadata.create_all(engine)
    with sessionmaker(bind=engine, expire_on_commit=False, future=True)() as session:
        yield session
    engine.dispose()


def test_upsert_catalog_csv_inserts_and_updates_authors_and_series(tmp_path, audiobook_session) -> None:
    audiobook_session.add_all(
        [
            AudiobookAuthor(id=10, name="old_author"),
            AudiobookAuthor(id=11, name="craig_alanson"),
        ],
    )
    audiobook_session.commit()
    authors_csv = tmp_path / "authors.csv"
    series_csv = tmp_path / "series.csv"
    authors_csv.write_text(
        "name,id\n"
        "glynn_stewart,\n"
        "craig_alanson,\n"
        "updated_author,10\n",
        encoding="utf-8",
    )
    series_csv.write_text(
        "name,author_name,id\n"
        "starships_mage,glynn_stewart,\n"
        "expeditionary_force,craig_alanson,\n",
        encoding="utf-8",
    )

    author_count = catalog.upsert_authors_from_csv(audiobook_session, authors_csv)
    series_count = catalog.upsert_series_from_csv(audiobook_session, series_csv)
    audiobook_session.commit()

    authors = audiobook_session.scalars(select(AudiobookAuthor).order_by(AudiobookAuthor.id)).all()
    series = audiobook_session.scalars(select(AudiobookSeries).order_by(AudiobookSeries.name)).all()
    assert author_count == 3
    assert series_count == 2
    assert [(author.id, author.name) for author in authors] == [
        (10, "updated_author"),
        (11, "craig_alanson"),
        (12, "glynn_stewart"),
    ]
    assert [(row.name, row.author.name) for row in series] == [
        ("expeditionary_force", "craig_alanson"),
        ("starships_mage", "glynn_stewart"),
    ]


def test_upsert_series_csv_updates_series_by_id(tmp_path, audiobook_session) -> None:
    author = AudiobookAuthor(id=1, name="glynn_stewart")
    audiobook_session.add_all(
        [
            author,
            AudiobookSeries(id=7, name="old_series", author=author),
        ],
    )
    audiobook_session.commit()
    series_csv = tmp_path / "series.csv"
    series_csv.write_text(
        "name,author_name,id\n"
        "starships_mage,glynn_stewart,7\n",
        encoding="utf-8",
    )

    count = catalog.upsert_series_from_csv(audiobook_session, series_csv)
    audiobook_session.commit()

    series = audiobook_session.get(AudiobookSeries, 7)
    assert count == 1
    assert series.name == "starships_mage"
    assert series.author.name == "glynn_stewart"


def test_upsert_csv_allows_missing_id_column(tmp_path, audiobook_session) -> None:
    authors_csv = tmp_path / "authors.csv"
    series_csv = tmp_path / "series.csv"
    authors_csv.write_text(
        "name\n"
        "glynn_stewart\n",
        encoding="utf-8",
    )
    series_csv.write_text(
        "name,author_name\n"
        "starships_mage,glynn_stewart\n",
        encoding="utf-8",
    )

    author_count = catalog.upsert_authors_from_csv(audiobook_session, authors_csv)
    series_count = catalog.upsert_series_from_csv(audiobook_session, series_csv)
    audiobook_session.commit()

    series = audiobook_session.scalar(select(AudiobookSeries))
    assert author_count == 1
    assert series_count == 1
    assert series.name == "starships_mage"
    assert series.author.name == "glynn_stewart"


def test_upsert_series_csv_rejects_unknown_author(tmp_path, audiobook_session) -> None:
    series_csv = tmp_path / "series.csv"
    series_csv.write_text(
        "name,author_name,id\n"
        "starships_mage,glynn_stewart,\n",
        encoding="utf-8",
    )

    with pytest.raises(catalog.CatalogImportError) as error:
        catalog.upsert_series_from_csv(audiobook_session, series_csv)

    assert "author not found: glynn_stewart" in str(error.value)
