"""
gemini_factory + package_exporter 单元测试
"""
import sys, os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))

import json
import tempfile
import zipfile
from pathlib import Path

import pytest

from app.services.ai_engine.gemini_factory import (
    build_ai_clients, _extract_image_bytes, _extract_gemini_image
)
from app.services.ai_engine.package_exporter import build_delivery_package


# ── gemini_factory ─────────────────────────────────────────
class TestGeminiFactory:
    def test_build_clients_returns_ai_clients(self, monkeypatch):
        monkeypatch.setenv("IMAGE_API_BASE", "https://api.example.com")
        clients = build_ai_clients(plain_key="test_key_1234")
        assert clients is not None
        assert clients._model == clients._model_text

    def test_model_property_uses_env(self, monkeypatch):
        monkeypatch.setenv("IMAGE_API_BASE", "https://api.example.com")
        monkeypatch.setenv("MODEL_TEXT", "gpt-5.5")
        clients = build_ai_clients(plain_key="test_key_1234")
        assert clients._model_text == "gpt-5.5"

    def test_extract_image_bytes_b64(self):
        import base64
        fake_png = b"\x89PNG fake"
        b64 = base64.b64encode(fake_png).decode()
        result = _extract_image_bytes({"data": [{"b64_json": b64}]})
        assert result == fake_png

    def test_extract_image_bytes_empty_raises(self):
        with pytest.raises(ValueError):
            _extract_image_bytes({"data": []})

    def test_extract_gemini_image_success(self):
        import base64
        fake_img = b"\xff\xd8\xff fake jpeg"
        b64 = base64.b64encode(fake_img).decode()
        resp = {"candidates": [{"content": {"parts": [{"inlineData": {"data": b64}}]}}]}
        result = _extract_gemini_image(resp)
        assert result == fake_img

    def test_extract_gemini_image_no_image_raises(self):
        resp = {"candidates": [{"content": {"parts": [{"text": "no image"}]}}]}
        with pytest.raises(ValueError):
            _extract_gemini_image(resp)

    def test_key_not_in_repr(self, monkeypatch):
        monkeypatch.setenv("IMAGE_API_BASE", "https://api.example.com")
        clients = build_ai_clients(plain_key="super_secret_key_xyz")
        # repr 不泄露 key
        assert "super_secret_key_xyz" not in repr(clients)


# ── package_exporter ──────────────────────────────────────
class TestPackageExporter:
    def _make_notes(self):
        return [{
            "title": "早八素颜也能有气色",
            "content": "姐妹们实测下来，轻薄不厚重是关键。✅ 通勤必备。",
            "tags": ["#素颜霜", "#日常通勤"],
            "images": [
                {"seq": 1, "role": "hook",  "data": b"\xff\xd8\xff fake_jpg_1"},
                {"seq": 2, "role": "proof", "data": b"\xff\xd8\xff fake_jpg_2"},
            ],
            "banned_word_status": "pass",
        }]

    def test_creates_zip(self, tmp_path):
        zip_path = build_delivery_package(
            workspace_id=1, task_id=99,
            notes=self._make_notes(),
            base_path=str(tmp_path),
        )
        assert Path(zip_path).exists()
        assert zip_path.endswith(".zip")

    def test_zip_contains_required_files(self, tmp_path):
        zip_path = build_delivery_package(
            workspace_id=1, task_id=99,
            notes=self._make_notes(),
            base_path=str(tmp_path),
        )
        with zipfile.ZipFile(zip_path) as zf:
            names = zf.namelist()
        # 应含文案.txt、发布清单、合规说明
        assert any("文案.txt" in n for n in names)
        assert any("发布清单" in n for n in names)
        assert any("合规说明" in n for n in names)

    def test_images_named_by_seq(self, tmp_path):
        zip_path = build_delivery_package(
            workspace_id=1, task_id=99,
            notes=self._make_notes(),
            base_path=str(tmp_path),
        )
        with zipfile.ZipFile(zip_path) as zf:
            names = zf.namelist()
        # 图片按 seq 序号命名
        assert any("01_hook.jpg" in n for n in names)
        assert any("02_proof.jpg" in n for n in names)

    def test_copy_txt_contains_title_and_tags(self, tmp_path):
        zip_path = build_delivery_package(
            workspace_id=1, task_id=99,
            notes=self._make_notes(),
            base_path=str(tmp_path),
        )
        with zipfile.ZipFile(zip_path) as zf:
            copy_txt = zf.read("note_01/文案.txt").decode("utf-8")
        assert "早八素颜也能有气色" in copy_txt
        assert "#素颜霜" in copy_txt

    def test_compliance_note_shows_status(self, tmp_path):
        zip_path = build_delivery_package(
            workspace_id=1, task_id=99,
            notes=self._make_notes(),
            base_path=str(tmp_path),
        )
        with zipfile.ZipFile(zip_path) as zf:
            compliance = zf.read("✅合规说明.txt").decode("utf-8")
        assert "✅通过" in compliance

    def test_no_images_still_creates_package(self, tmp_path):
        notes = [{**self._make_notes()[0], "images": []}]
        zip_path = build_delivery_package(
            workspace_id=1, task_id=100,
            notes=notes,
            base_path=str(tmp_path),
        )
        assert Path(zip_path).exists()
