#!/usr/bin/env python3
from __future__ import annotations

import asyncio
import os
import shutil
import sys
import tempfile
import unittest
from pathlib import Path


HERE = Path(__file__).resolve().parent
TEST_ROOT = Path(tempfile.mkdtemp(prefix="iterfact_chunked_test_"))
(TEST_ROOT / "generated").mkdir(parents=True, exist_ok=True)
(TEST_ROOT / "analytics").mkdir(parents=True, exist_ok=True)

os.environ["ITERFACT_OUTPUT_DIR"] = str(TEST_ROOT / "generated")
os.environ["ITERFACT_ANALYTICS_DIR"] = str(TEST_ROOT / "analytics")
os.environ["R2_BUCKET"] = ""
os.environ["R2_ACCESS_KEY_ID"] = ""
os.environ["R2_SECRET_ACCESS_KEY"] = ""
os.environ["R2_ACCOUNT_ID"] = ""
os.environ["ITERFACT_HEADLESS_VALIDATION_ENABLED"] = "0"
os.environ["ANTHROPIC_API_KEY"] = ""

if str(HERE) not in sys.path:
    sys.path.insert(0, str(HERE))

import server as mcp_server  # noqa: E402


CHESS_SOURCE = """CHESS OPENING QUIZ DATA

Question 1 - Difficulty: Easy
After 1.e4 e5 2.Nf3 Nc6 3.Bb5 what is this opening?
A) Ruy Lopez (CORRECT)
B) Italian Game
C) Scotch Game
D) Four Knights Game

Question 2 - Difficulty: Easy
After 1.e4 e5 2.Nf3 Nc6 3.Bc4 what is this opening?
A) Ruy Lopez
B) Italian Game (CORRECT)
C) Vienna Game
D) Petroff Defense

Question 3 - Difficulty: Medium
After 1.d4 Nf6 2.c4 e6 3.Nc3 Bb4 what defense is Black playing?
A) Queen's Gambit Declined
B) Nimzo-Indian Defense (CORRECT)
C) King's Indian Defense
D) Bogo-Indian Defense

Question 4 - Difficulty: Medium
After 1.e4 c5 2.Nf3 d6 3.d4 cxd4 4.Nxd4 Nf6 5.Nc3 a6 what variation is this?
A) Dragon
B) Najdorf (CORRECT)
C) Scheveningen
D) Classical Sicilian

Question 5 - Difficulty: Medium
After 1.e4 e6 what defense is Black choosing?
A) Caro-Kann
B) French Defense (CORRECT)
C) Pirc Defense
D) Scandinavian Defense

Question 6 - Difficulty: Hard
After 1.d4 d5 2.c4 e6 3.Nc3 Nf6 4.Bg5 Be7 what opening family is this?
A) Slav Defense
B) Queen's Gambit Declined (CORRECT)
C) Grunfeld Defense
D) Benoni Defense

Question 7 - Difficulty: Hard
After 1.e4 c6 what defense is Black choosing?
A) French Defense
B) Scandinavian Defense
C) Caro-Kann Defense (CORRECT)
D) Alekhine Defense

Question 8 - Difficulty: Hard
After 1.d4 Nf6 2.c4 g6 3.Nc3 Bg7 4.e4 d6 what defense is this?
A) King's Indian Defense (CORRECT)
B) Grunfeld Defense
C) Benko Gambit
D) Dutch Defense

Question 9 - Difficulty: Hard
After 1.e4 d5 2.exd5 Qxd5 what opening is Black playing?
A) Alekhine Defense
B) Scandinavian Defense (CORRECT)
C) Pirc Defense
D) Modern Defense

Question 10 - Difficulty: Hard
After 1.Nf3 d5 2.g3 c5 3.Bg2 Nc6 4.d4 what opening system is White steering toward?
A) English Opening
B) King's Indian Attack
C) Reti Opening (CORRECT)
D) Catalan Opening

SCORING PERSONALITY RESULTS:
0-3 correct: "The Patzer"
4-6 correct: "Club Player"
7-8 correct: "Opening Theorist"
9-10 correct: "Walking ECO Encyclopedia"
"""

ORG_SOURCE = "CEO: John Smith, CTO: Jane Doe, VP Eng: Bob Wilson"


class ChunkedBuildPathTests(unittest.IsolatedAsyncioTestCase):
    async def asyncSetUp(self) -> None:
        if TEST_ROOT.exists():
            shutil.rmtree(TEST_ROOT)
        (TEST_ROOT / "generated").mkdir(parents=True, exist_ok=True)
        (TEST_ROOT / "analytics").mkdir(parents=True, exist_ok=True)

    async def test_chunked_quiz_engine_override_uses_caller_source_text(self) -> None:
        draft = await mcp_server.create_artifact_draft(
            prompt="Chess opening quiz - 10 questions, interactive scoring, personality result at end",
            engine_override="09",
            section_count=1,
            theme_hint="dark, forest green #2D6A4F, teal #5DCAA5, near-black #0a0908",
            ctx=None,
        )
        artifact_id = draft["artifact_id"]
        state = mcp_server.load_artifact_state(artifact_id)

        self.assertEqual(draft.get("primary_engine_id"), "09")
        self.assertNotEqual(draft.get("wrapper_engine_id"), "24")
        self.assertEqual(len((state.get("plan") or {}).get("sections") or []), 0)

        append = await mcp_server.append_section(
            artifact_id=artifact_id,
            source_text=CHESS_SOURCE,
            section_title_hint="Chess Opening Quiz",
            ctx=None,
        )
        state = mcp_server.load_artifact_state(artifact_id)
        sections = (state.get("plan") or {}).get("sections") or []
        component = ((sections[0].get("components") or [None])[0]) if sections else None
        questions = (((component or {}).get("data") or {}).get("questions") or [])

        self.assertEqual(append["section_index"], 1)
        self.assertEqual((component or {}).get("engine"), "09")
        self.assertEqual(len(questions), 10)

        await mcp_server.finalize_artifact(
            artifact_id=artifact_id,
            skip_critic=True,
            wait_for_completion=True,
            ctx=None,
        )
        state = mcp_server.load_artifact_state(artifact_id)
        html = Path(state["current"]["local_path"]).read_text(encoding="utf-8")
        warning_types = {
            warning.get("type")
            for warning in (state.get("current") or {}).get("warnings") or []
            if isinstance(warning, dict)
        }

        self.assertIn("Ruy Lopez", html)
        self.assertIn("Walking ECO Encyclopedia", html)
        self.assertNotIn("capital of France", html)
        self.assertNotIn("event_wrapper_misuse", warning_types)
        self.assertNotIn("source_data_not_rendered", warning_types)

    async def test_chunked_org_chart_uses_caller_people_names(self) -> None:
        draft = await mcp_server.create_artifact_draft(
            prompt="Team directory for an executive team",
            engine_override="19",
            section_count=1,
            ctx=None,
        )
        artifact_id = draft["artifact_id"]

        append = await mcp_server.append_section(
            artifact_id=artifact_id,
            source_text=ORG_SOURCE,
            section_title_hint="Leadership Team",
            ctx=None,
        )
        self.assertEqual(append["section_index"], 1)

        await mcp_server.finalize_artifact(
            artifact_id=artifact_id,
            skip_critic=True,
            wait_for_completion=True,
            ctx=None,
        )
        state = mcp_server.load_artifact_state(artifact_id)
        html = Path(state["current"]["local_path"]).read_text(encoding="utf-8")

        self.assertIn("John Smith", html)
        self.assertIn("Jane Doe", html)
        self.assertIn("Bob Wilson", html)
        self.assertNotIn("Alex Chen", html)

    async def test_invalid_engine_override_raises(self) -> None:
        with self.assertRaises(ValueError):
            await mcp_server.create_artifact_draft(
                prompt="quiz",
                engine_override="99",
                section_count=1,
                ctx=None,
            )

    async def test_chunked_draft_without_override_still_creates(self) -> None:
        draft = await mcp_server.create_artifact_draft(
            prompt="quiz about chess",
            section_count=1,
            ctx=None,
        )
        self.assertTrue(draft["artifact_id"])


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