import pytest
from pathlib import Path

from services.archive import (
    Archive,
    ArchiveWelcome,
    Material,
    load_archive,
    save_archive,
    slugify,
    add_material,
    remove_material,
    set_welcome,
)


def test_slugify_russian_title_transliterates_to_ascii_kebab():
    result = slugify("Вебинар Бата · июнь 2026", existing_ids=[])
    assert result == "vebinar-bata-iyun-2026"


def test_slugify_strips_punctuation_and_collapses_spaces():
    result = slugify("Hello,  World!! ", existing_ids=[])
    assert result == "hello-world"


def test_slugify_appends_suffix_on_duplicate():
    result = slugify("Тест", existing_ids=["test"])
    assert result == "test-2"


def test_slugify_appends_incrementing_suffix():
    result = slugify("Тест", existing_ids=["test", "test-2", "test-3"])
    assert result == "test-4"


def test_slugify_hard_cap_50_chars():
    long_title = "A" * 100
    result = slugify(long_title, existing_ids=[])
    assert len(result) <= 50
    assert result == "a" * 50


def test_slugify_hard_cap_with_suffix_fits_in_53():
    long_title = "A" * 100
    result = slugify(long_title, existing_ids=["a" * 50])
    # truncated base "aaaa...aaa" (50 chars) + "-2" suffix
    assert result == "a" * 50 + "-2"
    assert len(result) <= 53


def test_slugify_empty_after_transliteration_falls_back():
    # title that has no ASCII-able characters (emoji only)
    result = slugify("🎬🎬🎬", existing_ids=[])
    assert result == "material"


def test_slugify_empty_fallback_with_duplicate():
    result = slugify("🎬", existing_ids=["material"])
    assert result == "material-2"


def test_load_archive_missing_file_returns_empty(tmp_path):
    result = load_archive(str(tmp_path / "does_not_exist.json"))
    assert result == Archive(welcome=None, materials=[])


def test_load_archive_with_full_content(tmp_path):
    p = tmp_path / "archive.json"
    p.write_text(
        '{"welcome": {"text": "Hi", "photo_file_id": "AbC123"}, '
        '"materials": [{"id": "m1", "title": "T", "description": "D", "url": "https://x"}]}',
        encoding="utf-8",
    )
    result = load_archive(str(p))
    assert result.welcome == ArchiveWelcome(text="Hi", photo_file_id="AbC123")
    assert result.materials == [Material(id="m1", title="T", description="D", url="https://x")]


def test_load_archive_with_null_welcome(tmp_path):
    p = tmp_path / "archive.json"
    p.write_text('{"welcome": null, "materials": []}', encoding="utf-8")
    result = load_archive(str(p))
    assert result.welcome is None
    assert result.materials == []


def test_save_then_load_round_trip(tmp_path):
    p = tmp_path / "archive.json"
    archive = Archive(
        welcome=ArchiveWelcome(text="<b>Hi</b>", photo_file_id=None),
        materials=[
            Material(id="bat", title="Бат", description="опис", url="https://yt.be/x"),
        ],
    )
    save_archive(str(p), archive)
    loaded = load_archive(str(p))
    assert loaded == archive


def test_save_archive_is_atomic_uses_tmp_rename(tmp_path):
    p = tmp_path / "archive.json"
    p.write_text("OLD", encoding="utf-8")
    archive = Archive(welcome=None, materials=[])
    save_archive(str(p), archive)
    # after save: real file contains valid JSON, no .tmp leftover
    assert "OLD" not in p.read_text(encoding="utf-8")
    assert not (tmp_path / "archive.json.tmp").exists()


def test_add_material_creates_with_slug_id_and_returns():
    archive = Archive(welcome=None, materials=[])
    mat = add_material(archive, title="Вебинар Бата · июнь 2026",
                      description="опис", url="https://yt.be/x")
    assert mat.id == "vebinar-bata-iyun-2026"
    assert mat.title == "Вебинар Бата · июнь 2026"
    assert mat.description == "опис"
    assert mat.url == "https://yt.be/x"
    assert archive.materials == [mat]


def test_add_material_appends_to_existing():
    archive = Archive(
        welcome=None,
        materials=[Material(id="first", title="F", description="", url="https://x")],
    )
    mat = add_material(archive, title="Second", description="", url="https://y")
    assert mat.id == "second"
    assert [m.id for m in archive.materials] == ["first", "second"]


def test_add_material_handles_duplicate_slug():
    archive = Archive(welcome=None, materials=[])
    add_material(archive, title="Тест", description="", url="https://a")
    second = add_material(archive, title="Тест", description="", url="https://b")
    assert second.id == "test-2"


def test_remove_material_returns_true_when_found():
    archive = Archive(
        welcome=None,
        materials=[
            Material(id="m1", title="A", description="", url="https://x"),
            Material(id="m2", title="B", description="", url="https://y"),
        ],
    )
    result = remove_material(archive, "m1")
    assert result is True
    assert [m.id for m in archive.materials] == ["m2"]


def test_remove_material_returns_false_when_not_found():
    archive = Archive(welcome=None, materials=[])
    result = remove_material(archive, "missing")
    assert result is False


def test_set_welcome_creates_new():
    archive = Archive(welcome=None, materials=[])
    set_welcome(archive, text="Hello", photo_file_id="abc")
    assert archive.welcome == ArchiveWelcome(text="Hello", photo_file_id="abc")


def test_set_welcome_overwrites_existing():
    archive = Archive(welcome=ArchiveWelcome(text="old", photo_file_id="old"), materials=[])
    set_welcome(archive, text="new", photo_file_id=None)
    assert archive.welcome == ArchiveWelcome(text="new", photo_file_id=None)
