"""generate_ai_image.py의 순수 함수에 대한 단위 테스트."""

import json
import sys
from pathlib import Path
from typing import Any

import pytest

sys.path.insert(0, str(Path(__file__).parent))

from generate_ai_image import (  # noqa: E402
    COST_TABLE,
    SCENARIOS,
    load_env_keys,
    load_results,
    save_results,
)

# ---------------------------------------------------------------------------
# load_env_keys
# ---------------------------------------------------------------------------


class TestLoadEnvKeys:
    def test_parse_key_value(self, tmp_path: Path) -> None:
        """KEY=VALUE 형식을 올바르게 파싱한다."""
        env_file = tmp_path / ".env.keys"
        env_file.write_text("FOO=bar\nBAZ=qux\n", encoding="utf-8")

        result = load_env_keys(env_file)

        assert result == {"FOO": "bar", "BAZ": "qux"}

    def test_parse_export_prefix(self, tmp_path: Path) -> None:
        """export KEY=VALUE 형식을 올바르게 파싱한다."""
        env_file = tmp_path / ".env.keys"
        env_file.write_text("export MY_KEY=my_value\n", encoding="utf-8")

        result = load_env_keys(env_file)

        assert result == {"MY_KEY": "my_value"}

    def test_strip_double_quotes(self, tmp_path: Path) -> None:
        """큰따옴표로 감싸진 값에서 따옴표를 제거한다."""
        env_file = tmp_path / ".env.keys"
        env_file.write_text('API_KEY="secret123"\n', encoding="utf-8")

        result = load_env_keys(env_file)

        assert result == {"API_KEY": "secret123"}

    def test_strip_single_quotes(self, tmp_path: Path) -> None:
        """작은따옴표로 감싸진 값에서 따옴표를 제거한다."""
        env_file = tmp_path / ".env.keys"
        env_file.write_text("API_KEY='secret456'\n", encoding="utf-8")

        result = load_env_keys(env_file)

        assert result == {"API_KEY": "secret456"}

    def test_ignore_empty_lines(self, tmp_path: Path) -> None:
        """빈 줄을 무시한다."""
        env_file = tmp_path / ".env.keys"
        env_file.write_text("\n\nFOO=bar\n\n", encoding="utf-8")

        result = load_env_keys(env_file)

        assert result == {"FOO": "bar"}

    def test_ignore_comment_lines(self, tmp_path: Path) -> None:
        """# 로 시작하는 주석 줄을 무시한다."""
        env_file = tmp_path / ".env.keys"
        env_file.write_text(
            "# 이것은 주석입니다\nFOO=bar\n# 또 다른 주석\n",
            encoding="utf-8",
        )

        result = load_env_keys(env_file)

        assert result == {"FOO": "bar"}

    def test_file_not_found_returns_empty_dict(self, tmp_path: Path) -> None:
        """존재하지 않는 파일에 대해 빈 dict를 반환한다."""
        missing_file = tmp_path / "does_not_exist.keys"

        result = load_env_keys(missing_file)

        assert result == {}

    def test_mixed_formats(self, tmp_path: Path) -> None:
        """다양한 형식이 혼합된 파일을 올바르게 파싱한다."""
        content = (
            "# comment\n"
            "\n"
            "PLAIN=value1\n"
            'QUOTED="value2"\n'
            "SINGLE='value3'\n"
            "export EXPORTED=value4\n"
            'export EXPORT_QUOTED="value5"\n'
        )
        env_file = tmp_path / ".env.keys"
        env_file.write_text(content, encoding="utf-8")

        result = load_env_keys(env_file)

        assert result == {
            "PLAIN": "value1",
            "QUOTED": "value2",
            "SINGLE": "value3",
            "EXPORTED": "value4",
            "EXPORT_QUOTED": "value5",
        }


# ---------------------------------------------------------------------------
# load_results
# ---------------------------------------------------------------------------


class TestLoadResults:
    def test_load_valid_json(self, tmp_path: Path) -> None:
        """올바른 JSON 파일을 로드한다."""
        data: list[dict[str, Any]] = [
            {"api": "gpt", "scenario": "A", "quality": "medium"},
            {"api": "gemini", "scenario": "B", "quality": "low"},
        ]
        results_file = tmp_path / "results.json"
        results_file.write_text(json.dumps(data), encoding="utf-8")

        result = load_results(results_file)

        assert result == data

    def test_file_not_found_returns_empty_list(self, tmp_path: Path) -> None:
        """존재하지 않는 파일에 대해 빈 list를 반환한다."""
        missing_file = tmp_path / "results.json"

        result = load_results(missing_file)

        assert result == []

    def test_load_empty_list(self, tmp_path: Path) -> None:
        """빈 배열 JSON을 로드한다."""
        results_file = tmp_path / "results.json"
        results_file.write_text("[]", encoding="utf-8")

        result = load_results(results_file)

        assert result == []


# ---------------------------------------------------------------------------
# save_results
# ---------------------------------------------------------------------------


class TestSaveResults:
    def test_save_and_reload(self, tmp_path: Path) -> None:
        """저장한 데이터를 다시 읽으면 동일한 내용이어야 한다."""
        data: list[dict[str, Any]] = [
            {
                "api": "gpt",
                "scenario": "A",
                "quality": "high",
                "cost_usd": 0.167,
                "error": None,
            }
        ]
        results_file = tmp_path / "results.json"

        save_results(results_file, data)
        reloaded = load_results(results_file)

        assert reloaded == data

    def test_save_creates_file(self, tmp_path: Path) -> None:
        """save_results 호출 후 파일이 생성된다."""
        results_file = tmp_path / "results.json"

        save_results(results_file, [])

        assert results_file.exists()

    def test_save_korean_text(self, tmp_path: Path) -> None:
        """한글 텍스트를 포함한 데이터를 손상 없이 저장한다."""
        data: list[dict[str, Any]] = [{"message": "한글 텍스트 테스트"}]
        results_file = tmp_path / "results.json"

        save_results(results_file, data)
        reloaded = load_results(results_file)

        assert reloaded[0]["message"] == "한글 텍스트 테스트"

    def test_save_uses_ensure_ascii_false(self, tmp_path: Path) -> None:
        """저장된 파일에 한글이 이스케이프 없이 저장된다."""
        data: list[dict[str, Any]] = [{"key": "한글"}]
        results_file = tmp_path / "results.json"

        save_results(results_file, data)
        raw_content = results_file.read_text(encoding="utf-8")

        assert "한글" in raw_content

    def test_overwrite_existing_file(self, tmp_path: Path) -> None:
        """기존 파일을 덮어쓴다."""
        results_file = tmp_path / "results.json"
        old_data: list[dict[str, Any]] = [{"old": True}]
        new_data: list[dict[str, Any]] = [{"new": True}]

        save_results(results_file, old_data)
        save_results(results_file, new_data)
        reloaded = load_results(results_file)

        assert reloaded == new_data


# ---------------------------------------------------------------------------
# SCENARIOS
# ---------------------------------------------------------------------------


class TestScenarios:
    def test_has_three_scenarios(self) -> None:
        """SCENARIOS dict에 3개의 시나리오가 존재한다."""
        assert len(SCENARIOS) == 3

    def test_scenario_keys_are_a_b_c(self) -> None:
        """SCENARIOS의 키는 A, B, C 이다."""
        assert set(SCENARIOS.keys()) == {"A", "B", "C"}

    def test_all_values_are_non_empty_strings(self) -> None:
        """모든 시나리오 값은 비어 있지 않은 문자열이다."""
        for key, value in SCENARIOS.items():
            assert isinstance(value, str), f"시나리오 {key}의 값이 str이 아닙니다."
            assert len(value) > 0, f"시나리오 {key}의 값이 비어 있습니다."


# ---------------------------------------------------------------------------
# COST_TABLE
# ---------------------------------------------------------------------------


class TestCostTable:
    def test_has_low_medium_high(self) -> None:
        """COST_TABLE에 low, medium, high 키가 존재한다."""
        assert set(COST_TABLE.keys()) == {"low", "medium", "high"}

    def test_low_cost(self) -> None:
        """low 비용은 0.011이다."""
        assert COST_TABLE["low"] == pytest.approx(0.011)

    def test_medium_cost(self) -> None:
        """medium 비용은 0.042이다."""
        assert COST_TABLE["medium"] == pytest.approx(0.042)

    def test_high_cost(self) -> None:
        """high 비용은 0.167이다."""
        assert COST_TABLE["high"] == pytest.approx(0.167)

    def test_all_costs_are_positive_floats(self) -> None:
        """모든 비용 값은 양수 float이다."""
        for quality, cost in COST_TABLE.items():
            assert isinstance(cost, float), f"{quality} 비용이 float이 아닙니다."
            assert cost > 0, f"{quality} 비용이 0 이하입니다."
