"""Tests for fetch_license_plates module - part 2 (generate + main)."""

from __future__ import annotations

from io import StringIO
from pathlib import Path
import tempfile
from unittest.mock import MagicMock, patch

from python_pkg.anki_decks.polish_license_plates.fetch_license_plates import (
    fetch_wikipedia_license_plates,
    generate_license_plate_data_file,
    main,
)

MOD = "python_pkg.anki_decks.polish_license_plates.fetch_license_plates"


# ── fetch_wikipedia_license_plates ───────────────────────────────────


class TestFetchWikipediaLicensePlates:
    """Tests for fetch_wikipedia_license_plates."""

    @patch(f"{MOD}.parse_license_plates_from_html", return_value={"WA": "Warszawa"})
    @patch(f"{MOD}.fetch_wikipedia_html", return_value="<html></html>")
    def test_combines_fetch_and_parse(
        self, mock_fetch: MagicMock, mock_parse: MagicMock
    ) -> None:
        result = fetch_wikipedia_license_plates()
        assert result == {"WA": "Warszawa"}
        mock_fetch.assert_called_once_with(force_refresh=False)
        mock_parse.assert_called_once_with("<html></html>")

    @patch(f"{MOD}.parse_license_plates_from_html", return_value={"KR": "Kraków"})
    @patch(f"{MOD}.fetch_wikipedia_html", return_value="<html></html>")
    def test_force_refresh_passed(
        self, mock_fetch: MagicMock, mock_parse: MagicMock
    ) -> None:
        fetch_wikipedia_license_plates(force_refresh=True)
        mock_fetch.assert_called_once_with(force_refresh=True)


# ── generate_license_plate_data_file ─────────────────────────────────


class TestGenerateLicensePlateDataFile:
    """Tests for generate_license_plate_data_file."""

    def test_generates_file_with_grouped_codes(self, tmp_path: Path) -> None:
        plates = {
            "WA": "Warszawa",
            "KR": "Kraków",
            "WB": "Warszawa-Bielany",
        }
        output = tmp_path / "license_plate_data.py"
        generate_license_plate_data_file(plates, output)
        content = output.read_text(encoding="utf-8")
        assert "LICENSE_PLATE_CODES" in content
        assert '"WA": "Warszawa"' in content
        assert '"KR": "Kraków"' in content
        assert '"WB": "Warszawa-Bielany"' in content
        # Grouped by voivodeship
        assert "# K - Małopolskie" in content
        assert "# W - Mazowieckie" in content

    def test_escapes_quotes_in_location(self, tmp_path: Path) -> None:
        plates = {"WA": 'Warszawa "capital"'}
        output = tmp_path / "out.py"
        generate_license_plate_data_file(plates, output)
        content = output.read_text(encoding="utf-8")
        assert '\\"capital\\"' in content

    def test_unknown_voivodeship_letter(self, tmp_path: Path) -> None:
        plates = {"XA": "Xanadu"}
        output = tmp_path / "out.py"
        generate_license_plate_data_file(plates, output)
        content = output.read_text(encoding="utf-8")
        assert "Voivodeship X" in content

    def test_writes_docstring_and_import(self, tmp_path: Path) -> None:
        plates = {"BA": "Białystok"}
        output = tmp_path / "out.py"
        generate_license_plate_data_file(plates, output)
        content = output.read_text(encoding="utf-8")
        assert "from __future__ import annotations" in content
        assert "Auto-generated by" in content

    def test_shows_code_count_per_voivodeship(self, tmp_path: Path) -> None:
        plates = {"BA": "Białystok", "BI": "Bielsk Podlaski"}
        output = tmp_path / "out.py"
        generate_license_plate_data_file(plates, output)
        content = output.read_text(encoding="utf-8")
        assert "(2 codes)" in content


# ── main ─────────────────────────────────────────────────────────────


class TestMain:
    """Tests for main entry point."""

    @patch(f"{MOD}.get_cache_path", return_value=Path(tempfile.gettempdir(), "cache"))
    @patch(f"{MOD}.generate_license_plate_data_file")
    @patch(
        f"{MOD}.fetch_wikipedia_license_plates",
        return_value={"WA": "Warszawa", "KR": "Kraków"},
    )
    @patch(f"{MOD}.argparse.ArgumentParser.parse_args")
    def test_success(
        self,
        mock_args: MagicMock,
        mock_fetch: MagicMock,
        mock_gen: MagicMock,
        mock_cache: MagicMock,
    ) -> None:
        mock_args.return_value = MagicMock(force=False)
        with patch("sys.stdout", new_callable=StringIO):
            result = main()
        assert result == 0
        mock_gen.assert_called_once()

    @patch(
        f"{MOD}.fetch_wikipedia_license_plates",
        side_effect=RuntimeError("network fail"),
    )
    @patch(f"{MOD}.argparse.ArgumentParser.parse_args")
    def test_runtime_error(
        self,
        mock_args: MagicMock,
        mock_fetch: MagicMock,
    ) -> None:
        mock_args.return_value = MagicMock(force=False)
        with patch("sys.stderr", new_callable=StringIO):
            result = main()
        assert result == 1

    @patch(f"{MOD}.get_cache_path", return_value=Path(tempfile.gettempdir(), "cache"))
    @patch(f"{MOD}.generate_license_plate_data_file")
    @patch(
        f"{MOD}.fetch_wikipedia_license_plates",
        return_value={"WA": "Warszawa"},
    )
    @patch(f"{MOD}.argparse.ArgumentParser.parse_args")
    def test_force_flag(
        self,
        mock_args: MagicMock,
        mock_fetch: MagicMock,
        mock_gen: MagicMock,
        mock_cache: MagicMock,
    ) -> None:
        mock_args.return_value = MagicMock(force=True)
        with patch("sys.stdout", new_callable=StringIO):
            result = main()
        assert result == 0
        mock_fetch.assert_called_once_with(force_refresh=True)

    @patch(f"{MOD}.get_cache_path", return_value=Path(tempfile.gettempdir(), "cache"))
    @patch(f"{MOD}.generate_license_plate_data_file")
    @patch(
        f"{MOD}.fetch_wikipedia_license_plates",
        return_value={"WA": "Warszawa"},
    )
    @patch(f"{MOD}.argparse.ArgumentParser.parse_args")
    def test_prints_summary(
        self,
        mock_args: MagicMock,
        mock_fetch: MagicMock,
        mock_gen: MagicMock,
        mock_cache: MagicMock,
    ) -> None:
        mock_args.return_value = MagicMock(force=False)
        with patch("sys.stdout", new_callable=StringIO) as mock_stdout:
            main()
        output = mock_stdout.getvalue()
        assert "Total codes" in output
        assert "LICENSE PLATE DATA UPDATE COMPLETE" in output
