"""통합 테스트 — image_router.py + iptc_tagger.py 연동.

테스트 범위:
- _generate_gemini() 실제 API 호출 구조 (gcloud_auth + REST API mock)
- _generate_satori() subprocess 호출 구조 (node subprocess mock)
- _generate_hybrid() generate_hybrid 모듈 호출 구조 (playwright mock)
- _generate_gpt() OpenAI API 호출 구조 (openai mock)
- generate_image() + iptc_tagger 연동 (IPTC 태깅이 성공 시 호출되는지)
"""

import sys
import json
from pathlib import Path
from unittest.mock import MagicMock, patch, call
import pytest

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

import image_router
from image_router import GenerationResult, generate_image


# ─────────────────────────────────────────────────────────────────────────────
# TestGenerateGeminiIntegration
# ─────────────────────────────────────────────────────────────────────────────


class TestGenerateGeminiIntegration:
    def test_gemini_calls_gcloud_auth_get_access_token(self, tmp_path: Path) -> None:
        """_generate_gemini() 호출 시 gcloud_auth.get_access_token 호출됨."""
        mock_gcloud = MagicMock()
        mock_gcloud.get_access_token.return_value = "fake_token"

        mock_gemini_gen = MagicMock()

        def side_effect_create_file(token, prompt, output_path, scenario):
            output_path.write_bytes(b"fake_image_data")

        mock_gemini_gen.generate_image_via_gemini_api.side_effect = side_effect_create_file

        with patch.dict("sys.modules", {
            "gcloud_auth": mock_gcloud,
            "gemini_pro_generate": mock_gemini_gen,
        }):
            # 모듈 캐시 초기화 후 재임포트
            if "image_router" in sys.modules:
                del sys.modules["image_router"]
            import importlib
            import image_router as _ir
            result = _ir._generate_gemini("테스트 프롬프트", tmp_path / "test.png")

        mock_gcloud.get_access_token.assert_called_once()
        assert result is True

    def test_gemini_returns_false_on_auth_failure(self, tmp_path: Path) -> None:
        """gcloud_auth 예외 시 False 반환."""
        mock_gcloud = MagicMock()
        mock_gcloud.get_access_token.side_effect = RuntimeError("인증 실패")

        mock_gemini_gen = MagicMock()

        with patch.dict("sys.modules", {
            "gcloud_auth": mock_gcloud,
            "gemini_pro_generate": mock_gemini_gen,
        }):
            if "image_router" in sys.modules:
                del sys.modules["image_router"]
            import importlib
            import image_router as _ir
            result = _ir._generate_gemini("테스트 프롬프트", tmp_path / "test.png")

        assert result is False


# ─────────────────────────────────────────────────────────────────────────────
# TestGenerateSatoriIntegration
# ─────────────────────────────────────────────────────────────────────────────


class TestGenerateSatoriIntegration:
    def test_satori_calls_node_subprocess(self, tmp_path: Path) -> None:
        """_generate_satori() 호출 시 subprocess.run이 'node'를 첫 인자로 호출."""
        output_path = tmp_path / "output.png"

        def fake_subprocess_run(cmd, *args, **kwargs):
            # node 호출 시 파일 생성 시뮬레이션
            if cmd and cmd[0] == "node":
                output_path.write_bytes(b"fake_png_data")
            mock_result = MagicMock()
            mock_result.returncode = 0
            return mock_result

        with patch("image_router.subprocess") as mock_subprocess:
            mock_subprocess.run.side_effect = fake_subprocess_run
            mock_subprocess.CalledProcessError = __import__("subprocess").CalledProcessError
            result = image_router._generate_satori("카드뉴스 프롬프트", output_path)

        # subprocess.run이 호출되었고 첫 인자 리스트의 첫 요소가 'node'인지 확인
        assert mock_subprocess.run.called
        call_args = mock_subprocess.run.call_args
        cmd = call_args[0][0] if call_args[0] else call_args[1].get("args", [])
        assert cmd[0] == "node"
        assert result is True

    def test_satori_returns_false_on_subprocess_error(self, tmp_path: Path) -> None:
        """subprocess.run returncode != 0 시 False 반환."""
        output_path = tmp_path / "output.png"

        def fake_subprocess_run_fail(cmd, *args, **kwargs):
            mock_result = MagicMock()
            mock_result.returncode = 1
            mock_result.stderr = "node 실행 오류"
            return mock_result

        with patch("image_router.subprocess") as mock_subprocess:
            mock_subprocess.run.side_effect = fake_subprocess_run_fail
            mock_subprocess.CalledProcessError = __import__("subprocess").CalledProcessError
            result = image_router._generate_satori("실패 프롬프트", output_path)

        assert result is False


# ─────────────────────────────────────────────────────────────────────────────
# TestGenerateHybridIntegration
# ─────────────────────────────────────────────────────────────────────────────


class TestGenerateHybridIntegration:
    def test_hybrid_returns_false_when_bg_missing(self, tmp_path: Path) -> None:
        """bg_A.jpg가 없으면 False 반환 (generate_hybrid 모듈 mock)."""
        mock_gen_hybrid = MagicMock()
        # bg 파일이 없으므로 FileNotFoundError 발생 시뮬레이션
        mock_gen_hybrid.generate_hybrid.side_effect = FileNotFoundError(
            "배경 이미지를 찾을 수 없습니다: bg_A.jpg"
        )

        with patch.dict("sys.modules", {"generate_hybrid": mock_gen_hybrid}):
            if "image_router" in sys.modules:
                del sys.modules["image_router"]
            import image_router as _ir
            result = _ir._generate_hybrid("하이브리드 프롬프트", tmp_path / "output.png")

        assert result is False


# ─────────────────────────────────────────────────────────────────────────────
# TestIptcTaggingIntegration
# ─────────────────────────────────────────────────────────────────────────────


class TestIptcTaggingIntegration:
    def test_iptc_tagger_called_after_successful_generation(
        self, tmp_path: Path
    ) -> None:
        """generate_image()에서 성공 후 iptc_tagger.tag_image가 호출되는지 확인.

        image_router.py 내부에서 'import iptc_tagger as _tagger' (lazy import) 방식 사용.
        sys.modules 패치로 해당 import를 가로챈다.
        """
        mock_iptc = MagicMock()
        output_png = tmp_path / "brand_gemini.png"
        mock_iptc.tag_image.return_value = output_png

        def fake_generate_gemini(prompt, output_path):
            # 유효한 PNG 파일 생성 (PIL이 인식할 수 있도록)
            from PIL import Image
            img = Image.new("RGB", (10, 10), color=(0, 0, 255))
            img.save(str(output_path), format="PNG")
            return True

        with (
            patch("image_router._generate_gemini", side_effect=fake_generate_gemini),
            patch.dict("sys.modules", {"iptc_tagger": mock_iptc}),
        ):
            result = generate_image(
                purpose="photorealistic",
                prompt="테스트 프롬프트",
                brand="brand",
                output_dir=tmp_path,
            )

        assert result.success is True
        mock_iptc.tag_image.assert_called_once()

    def test_iptc_tagging_failure_does_not_affect_result(
        self, tmp_path: Path
    ) -> None:
        """IPTC 태깅 실패해도 GenerationResult.success = True.

        image_router.py가 iptc_tagger 예외를 try/except로 무시하고 success를 반환해야 한다.
        """
        mock_iptc = MagicMock()
        mock_iptc.tag_image.side_effect = RuntimeError("IPTC 태깅 실패")

        def fake_generate_gemini(prompt, output_path):
            from PIL import Image
            img = Image.new("RGB", (10, 10), color=(0, 0, 255))
            img.save(str(output_path), format="PNG")
            return True

        with (
            patch("image_router._generate_gemini", side_effect=fake_generate_gemini),
            patch.dict("sys.modules", {"iptc_tagger": mock_iptc}),
        ):
            result = generate_image(
                purpose="photorealistic",
                prompt="태깅 실패 테스트",
                brand="brand",
                output_dir=tmp_path,
            )

        assert result.success is True
