"""Tests for BookPathGenerator."""

from pathlib import Path

from chitai.services.filesystem_library import BookPathGenerator, sanitize_path_component


ROOT = Path("/library")


def path_for(**book) -> Path:
    return BookPathGenerator(ROOT).generate_path(book)


def test_author_and_title() -> None:
    assert path_for(title="Dune", authors=["Frank Herbert"]) == (
        ROOT / "Frank Herbert" / "Dune"
    )


def test_a_book_with_no_authors() -> None:
    assert path_for(title="Beowulf", authors=[]) == ROOT / "Unknown" / "Beowulf"


def test_a_series_adds_a_level_and_pads_the_position() -> None:
    assert path_for(
        title="Persepolis Rising",
        authors=["James S. A. Corey"],
        series="The Expanse",
        series_position="7",
    ) == ROOT / "James S. A. Corey" / "The Expanse" / "07 - Persepolis Rising"


def test_a_slash_in_a_title_does_not_add_a_directory() -> None:
    """
    The separators in the path come from the template, never from the metadata.

    A title with a slash in it — "AC/DC", "Him/Her" — would otherwise put the book one
    level below where `book.path` says it is, which is what deletes, moves and file
    lookups all act on. Calibre keeps the real title in its database and strips this
    from its own directory names, so an import is where they surface.
    """
    generated = path_for(title="Back in Black: AC/DC", authors=["Murray Engleheart"])

    assert generated == ROOT / "Murray Engleheart" / "Back in Black: AC_DC"
    assert generated.relative_to(ROOT).parts == ("Murray Engleheart", "Back in Black: AC_DC")


def test_a_slash_in_an_author_or_series_is_handled_too() -> None:
    assert path_for(title="Split", authors=["A/B Collective"]) == (
        ROOT / "A_B Collective" / "Split"
    )
    assert path_for(
        title="Volume One", authors=["Someone"], series="Either/Or", series_position="1"
    ) == ROOT / "Someone" / "Either_Or" / "01 - Volume One"


def test_control_characters_are_removed() -> None:
    assert path_for(title="Line\nBreak", authors=["Someone"]) == (
        ROOT / "Someone" / "Line_Break"
    )


def test_sanitize_path_component() -> None:
    assert sanitize_path_component("AC/DC") == "AC_DC"
    assert sanitize_path_component("back\\slash") == "back_slash"
    assert sanitize_path_component("  padded  ") == "padded"
    # Colons and other punctuation are legal in a path and are left alone.
    assert sanitize_path_component("Title: Subtitle") == "Title: Subtitle"
