"""Unit-тесты для ET-011 sanitize/safe_filename (UT-04, REQ-F-04)."""
from __future__ import annotations

import urllib.parse

from src.api.gps_tracks.export import safe_filename


def test_ut04_cyrillic_utf8():
    """UT-04: кириллическое имя → ascii-fallback пустой и читается из utf-8."""
    name = "По грязи к Чёрному озеру"
    ascii_fb, utf8_quoted = safe_filename(name, 42)

    # ascii_fallback содержит только ASCII (после санитизации
    # нелатинские символы стали '_'), длина ≤ 80
    assert all(ord(c) < 128 for c in ascii_fb)
    assert len(ascii_fb) <= 80

    # decoded utf-8 совпадает с исходным именем (до триммирования по 80 байтам)
    decoded = urllib.parse.unquote(utf8_quoted, encoding="utf-8")
    assert decoded == name


def test_ut04_forbidden_chars_replaced():
    """UT-04: запрещённые ФС-символы → '_'."""
    name = 'Trail/with:bad*chars?"<>|'
    ascii_fb, _ = safe_filename(name, 1)
    for ch in '/\\:*?"<>|':
        assert ch not in ascii_fb
    # должно быть несколько подчёркиваний (хотя бы один на запрещённый символ)
    assert "_" in ascii_fb


def test_ut04_empty_name_fallback_track_id():
    """UT-04: пустое имя → 'track-<id>'."""
    ascii_fb, utf8_q = safe_filename("", 42)
    assert ascii_fb == "track-42"
    assert urllib.parse.unquote(utf8_q) == "track-42"


def test_ut04_none_name_fallback_track_id():
    ascii_fb, utf8_q = safe_filename(None, 7)
    assert ascii_fb == "track-7"
    assert urllib.parse.unquote(utf8_q) == "track-7"


def test_ut04_truncated_to_80_bytes():
    """UT-04: длинное ASCII-имя триммится до 80 байт."""
    name = "X" * 200
    ascii_fb, utf8_q = safe_filename(name, 1)
    assert len(ascii_fb.encode("utf-8")) <= 80
    # utf8_q после percent-decoding тоже не должен превышать лимит
    decoded = urllib.parse.unquote(utf8_q, encoding="utf-8")
    assert len(decoded.encode("utf-8")) <= 80


def test_ut04_truncated_utf8_no_broken_codepoints():
    """UT-04: триммирование multibyte-строки не ломает code-point."""
    # 200 русских букв = 400 байт UTF-8; триммим до 80 байт → ~40 букв
    name = "Я" * 200
    ascii_fb, utf8_q = safe_filename(name, 1)
    decoded = urllib.parse.unquote(utf8_q, encoding="utf-8")
    # должно успешно декодироваться
    assert len(decoded) > 0
    assert len(decoded.encode("utf-8")) <= 80


def test_ut04_only_forbidden_chars_fallback():
    """UT-04: имя из одних запрещённых символов после strip → fallback."""
    ascii_fb, utf8_q = safe_filename("...", 5)
    # точки страйпятся, остаётся пустота → fallback
    assert ascii_fb == "track-5"


def test_ut04_whitespace_only_fallback():
    ascii_fb, _ = safe_filename("   ", 8)
    assert ascii_fb == "track-8"


def test_ut04_control_chars_replaced():
    """Управляющие символы (0x00..0x1F, 0x7F) → '_'."""
    name = "abc\x00\x01\x1fdef\x7f"
    ascii_fb, _ = safe_filename(name, 1)
    assert "\x00" not in ascii_fb
    assert "\x1f" not in ascii_fb
    assert "\x7f" not in ascii_fb
    assert "abc" in ascii_fb and "def" in ascii_fb


def test_ut04_ascii_clean_kept_as_is():
    """ASCII-чистое имя сохраняется в ascii-fallback."""
    name = "OSM Trail 42"
    ascii_fb, utf8_q = safe_filename(name, 1)
    assert ascii_fb == "OSM Trail 42"
    assert urllib.parse.unquote(utf8_q) == "OSM Trail 42"
