#!/usr/bin/env python3
"""Fixture tests for the nAvid editorial media pilot contract."""

from __future__ import annotations

import json
from pathlib import Path
import subprocess
import sys
import tempfile
import unittest


VALIDATOR = Path(__file__).with_name("validate_pilot_output.py")
REPO_URL = "https://github.com/Lum1104/Understand-Anything"


class EditorialMediaTests(unittest.TestCase):
    def setUp(self) -> None:
        self.temp = tempfile.TemporaryDirectory()
        self.project = Path(self.temp.name) / "understand-anything-ai-news-vi"
        for directory in ("capture/screenshots", "renders"):
            (self.project / directory).mkdir(parents=True, exist_ok=True)
        self.write_valid_project()

    def tearDown(self) -> None:
        self.temp.cleanup()

    def write_text(self, relative: str, content: str) -> None:
        path = self.project / relative
        path.parent.mkdir(parents=True, exist_ok=True)
        path.write_text(content, encoding="utf-8")

    def write_json(self, relative: str, value: object) -> None:
        self.write_text(relative, json.dumps(value, ensure_ascii=False, indent=2))

    def read_json(self, relative: str) -> dict:
        return json.loads((self.project / relative).read_text(encoding="utf-8"))

    def write_valid_project(self) -> None:
        state = {
            "template_selection": {"id": "repo-update-fullframe", "tier": "approved"},
            "stages": {
                "voice": {"status": "complete", "metadata": {"provider": "OmniVoice", "profile": "76d11b96", "duration_seconds": "52.4"}},
                "composition": {"status": "complete"},
                "render": {"status": "complete"},
                "qa": {"status": "complete"},
            },
            "events": [],
        }
        source = {
            "primary_source": {"url": REPO_URL, "type": "official-repository"},
            "claims": [{"id": "C-01", "source_url": REPO_URL, "role": "SOURCE PROOF"}],
            "assets": [{"path": "capture/screenshots/readme-graph.png", "role": "SOURCE PROOF", "kind": "official-crop", "public": True}],
            "reference_video_policy": {"used_in_public_output": False},
        }
        qa = {"checks": {item: "pass" for item in (
            "source_traceability", "crop_legibility", "truth_roles",
            "vietnamese_rendering", "reference_video_nonreuse",
            "safe_zones", "timing_sync", "fallback_disclosure"
        )}}
        self.write_json("run-state.json", state)
        self.write_json("capture/source-record.json", source)
        self.write_json("capture/qa-report.json", qa)
        self.write_text("capture/visual-evidence-plan.md", "SOURCE PROOF focused crop\nEXPLAINER rebuilt path\nNo captured reference video output.\n")
        self.write_text("capture/screenshots/readme-graph.png", "proof")
        self.write_text("SCRIPT.md", "## Publish Title\nTool map\n## Source Notes\nOfficial README\n## Voiceover\n" + "A" * 100 + "\n## Truth Boundary\nVerify code.\n")
        self.write_text("PUBLISH.md", "## Publish Title\nTool map\n\n## Post Caption\nKhám phá dự án từ nguồn chính thức.\n\n## Hashtags\n#AINews247 #OpenSource #DeveloperTools #AIAgents #RAG\n")
        self.write_text("STORYBOARD.md", "Scene 2: SOURCE PROOF\nScene 4: EXPLAINER\nScene 7: CTA\n")
        self.write_text("voiceover.txt", "Noi dung ky thuat co nguon chinh thuc va can kiem tra code truoc khi sua. " * 3)
        self.write_text("narration.wav", "audio")
        self.write_text("index.html", "<html>SOURCE PROOF EXPLAINER</html>")
        self.write_text("renders/understand-anything-ai-news-vi.mp4", "video")
        self.write_text("capture/standard-contact-sheet.jpg", "sheet")
        self.write_text("HANDOFF.md", "OmniVoice and QA handoff complete.\n\n## Social Publish Kit\n- Publish Title: Tool map\n- Hashtags: #AINews247 #OpenSource #DeveloperTools #AIAgents #RAG\n")

    def run_validator(self, stage: str = "final") -> tuple[int, dict]:
        result = subprocess.run(
            [sys.executable, "-X", "utf8", str(VALIDATOR), "--project-dir", str(self.project), "--stage", stage],
            check=False, capture_output=True, text=True, encoding="utf-8",
        )
        return result.returncode, json.loads(result.stdout)

    def assert_failure_contains(self, needle: str) -> None:
        code, report = self.run_validator()
        self.assertNotEqual(0, code)
        self.assertTrue(any(needle in error for error in report["errors"]), report["errors"])

    def test_compliant_pilot_passes_final_validation(self) -> None:
        code, report = self.run_validator()
        self.assertEqual(0, code)
        self.assertEqual("pass", report["checks"])

    def test_missing_first_party_source_record_is_rejected(self) -> None:
        (self.project / "capture/source-record.json").unlink()
        self.assert_failure_contains("source-record.json")

    def test_scene_without_media_truth_roles_is_rejected(self) -> None:
        self.write_text("STORYBOARD.md", "Scene 7: CTA\n")
        self.assert_failure_contains("SOURCE PROOF")

    def test_public_reference_video_asset_is_rejected(self) -> None:
        source = self.read_json("capture/source-record.json")
        source["assets"].append({"path": "capture/screenshots/ref.png", "kind": "reference-video", "public": True, "role": "ILLUSTRATION"})
        self.write_text("capture/screenshots/ref.png", "unsafe")
        self.write_json("capture/source-record.json", source)
        self.assert_failure_contains("reference-video capture")

    def test_missing_measured_duration_is_rejected(self) -> None:
        state = self.read_json("run-state.json")
        del state["stages"]["voice"]["metadata"]["duration_seconds"]
        self.write_json("run-state.json", state)
        self.assert_failure_contains("measured narration duration")

    def test_undeclared_voice_fallback_is_rejected(self) -> None:
        state = self.read_json("run-state.json")
        state["stages"]["voice"]["metadata"]["provider"] = "Another Provider"
        self.write_json("run-state.json", state)
        self.assert_failure_contains("fallback approval")

    def test_missing_qa_and_handoff_is_rejected(self) -> None:
        (self.project / "capture/qa-report.json").unlink()
        (self.project / "HANDOFF.md").unlink()
        self.assert_failure_contains("qa-report.json")
        self.assert_failure_contains("HANDOFF.md")

    def test_missing_publish_package_is_rejected(self) -> None:
        (self.project / "PUBLISH.md").unlink()
        self.assert_failure_contains("PUBLISH.md")

    def test_handoff_without_hashtags_is_rejected(self) -> None:
        self.write_text("HANDOFF.md", "Publish Title: Tool map\n")
        self.assert_failure_contains("Hashtags")


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