"""core/pptx_guard.py 的 focused tests——「整页贴图」伪 pptx 判定。

用 python-pptx 真实构造两类 deck:光栅贴图(每页一张整版图、零文本)必须命中;
正常/边界 deck(有文本、大背景图配文字、单页、含表格)必须放行。
"""
import io
import time
import unittest
from pathlib import Path
from tempfile import TemporaryDirectory

from pptx import Presentation
from pptx.util import Emu, Inches

from core import pptx_guard


def _png_bytes() -> io.BytesIO:
    from PIL import Image

    buf = io.BytesIO()
    Image.new("RGB", (32, 18), (200, 30, 30)).save(buf, format="PNG")
    buf.seek(0)
    return buf


def _make_deck(path: Path, pages: list[dict]) -> Path:
    """pages: [{'pic': 覆盖率 0~1 或 None, 'text': str}]"""
    prs = Presentation()
    blank = prs.slide_layouts[6]
    sw, sh = prs.slide_width, prs.slide_height
    for spec in pages:
        slide = prs.slides.add_slide(blank)
        ratio = spec.get("pic")
        if ratio:
            side = ratio ** 0.5  # 面积占比 → 边长占比
            slide.shapes.add_picture(
                _png_bytes(), 0, 0, Emu(int(sw * side)), Emu(int(sh * side)))
        text = spec.get("text")
        if text:
            box = slide.shapes.add_textbox(
                Inches(1), Inches(1), Inches(4), Inches(1))
            box.text_frame.text = text
    prs.save(str(path))
    return path


class RasterDeckDetectionTests(unittest.TestCase):
    def test_full_page_paste_deck_is_flagged(self):
        with TemporaryDirectory() as tmp:
            p = _make_deck(Path(tmp) / "fake.pptx",
                           [{"pic": 1.0}] * 3)
            self.assertIsNotNone(pptx_guard.check_raster_deck(p))

    def test_native_text_deck_passes(self):
        with TemporaryDirectory() as tmp:
            p = _make_deck(Path(tmp) / "native.pptx",
                           [{"text": "标题"}, {"text": "正文要点"}])
            self.assertIsNone(pptx_guard.check_raster_deck(p))

    def test_big_background_with_text_passes(self):
        with TemporaryDirectory() as tmp:
            p = _make_deck(Path(tmp) / "bg.pptx",
                           [{"pic": 1.0, "text": "封面标题"},
                            {"pic": 0.95, "text": "章节页"}])
            self.assertIsNone(pptx_guard.check_raster_deck(p))

    def test_single_slide_poster_passes(self):
        with TemporaryDirectory() as tmp:
            p = _make_deck(Path(tmp) / "poster.pptx", [{"pic": 1.0}])
            self.assertIsNone(pptx_guard.check_raster_deck(p))

    def test_small_pictures_no_text_passes(self):
        # 图片没铺满整版(<85%)就不算贴图页,哪怕全 deck 无文本
        with TemporaryDirectory() as tmp:
            p = _make_deck(Path(tmp) / "album.pptx",
                           [{"pic": 0.5}, {"pic": 0.5}])
            self.assertIsNone(pptx_guard.check_raster_deck(p))

    def test_unparseable_file_passes(self):
        with TemporaryDirectory() as tmp:
            p = Path(tmp) / "broken.pptx"
            p.write_bytes(b"PK\x03\x04 not a real pptx")
            self.assertIsNone(pptx_guard.check_raster_deck(p))


class ScanTests(unittest.TestCase):
    def test_scan_reports_new_bad_deck_and_skips_hidden_and_old(self):
        with TemporaryDirectory() as tmp:
            root = Path(tmp)
            since = time.time()
            _make_deck(root / "bad.pptx", [{"pic": 1.0}] * 2)
            hidden = root / ".build"
            hidden.mkdir()
            _make_deck(hidden / "ignored.pptx", [{"pic": 1.0}] * 2)
            msg = pptx_guard.scan_and_report(root, since)
            self.assertIsNotNone(msg)
            self.assertIn("bad.pptx", msg)
            self.assertIn("[产物机检 ERROR]", msg)
            self.assertNotIn("ignored.pptx", msg)
            # 早于 since 的文件不复检
            self.assertIsNone(
                pptx_guard.scan_and_report(root, time.time() + 60))

    def test_scan_clean_dir_returns_none(self):
        with TemporaryDirectory() as tmp:
            root = Path(tmp)
            _make_deck(root / "ok.pptx", [{"text": "有字"}, {"text": "有字"}])
            self.assertIsNone(pptx_guard.scan_and_report(root, time.time() - 60))


if __name__ == "__main__":
    unittest.main()
