"""
Adversarial Verification Test Suite: Anti-Male-Tears Directive & Character Roster Lines 17-20
Project: Thập Ngũ Niên (The Fifteen Springs) - EP01
Challenger: teamwork_preview_challenger (M1 Iteration 2 Challenger 1)

Empirical Challenge Objectives:
1. Scan lines 17-20 and the entire Character Roster table for male characters associated with weeping keywords:
   - khóc, rơi lệ, giọt lệ, ngấn lệ, đầm đìa, châu sa (plus variations: nước mắt, gào khóc, nấc nghẹn, etc.).
2. Scan the full 188-shot screenplay across all 15 scenes for any male character crying/weeping.
3. Confirm 0 occurrences.
4. Execute official test suites and stress harnesses.
"""

import sys
import os
import re
import json
import unittest
from pathlib import Path

# Ensure UTF-8 output on Windows
if sys.stdout.encoding != 'utf-8':
    try:
        sys.stdout.reconfigure(encoding='utf-8')
    except Exception:
        pass

BASE_DIR = Path(__file__).resolve().parent.parent
FILMMAKER_DIR = BASE_DIR / "FilmMaker"
TAP01_PATH = FILMMAKER_DIR / "TAP_01_XUAN_SAC_THE_NGUYEN_VA_GIONG_BAO_DOAN_TRUONG.md"

sys.path.insert(0, str(BASE_DIR))
from tests import read_ep01_screenplay, find_male_crying_violations, get_screenplay_scenes, MALE_CHARACTERS

TARGET_WEEPING_KEYWORDS = [
    "khóc", "rơi lệ", "giọt lệ", "ngấn lệ", "đầm đìa", "châu sa"
]

EXTENDED_WEEPING_KEYWORDS = [
    "khóc", "rơi lệ", "giọt lệ", "ngấn lệ", "đầm đìa", "châu sa",
    "nước mắt", "rơi nước mắt", "gào khóc", "khóc than", "khóc ngất",
    "khóc rống", "nấc nghẹn", "sụt sùi", "thút thít", "châu tuôn",
    "lệ rơi", "lệ tràn", "đẫm lệ", "chan chứa giọt lệ"
]

ALL_MALE_CHARACTERS = [
    "KIM TRỌNG", "Kim Trọng", "Kim sinh", "chàng Kim",
    "VƯƠNG QUAN", "Vương Quan",
    "VƯƠNG ÔNG", "Vương Ông", "Vương viên ngoại", "cụ ông", "cha Kiều",
    "TỪ HẢI", "Từ Hải",
    "THÚC SINH", "Thúc Sinh", "THÚC ÔNG", "Thúc Ông",
    "MÃ GIÁM SINH", "Mã Giám Sinh",
    "SỞ KHANH", "Sở Khanh",
    "HỒ TÔN HIẾN", "Hồ Tôn Hiến",
    "BẠC HẠNH", "Bạc Hạnh"
]


class TestAdversarialMaleWeepingM1(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        with open(TAP01_PATH, "r", encoding="utf-8") as f:
            cls.screenplay_text = f.read()
        cls.lines = cls.screenplay_text.splitlines()

    def test_01_lines_17_to_20_exact_zero_target_keywords(self):
        """Challenge 1: Verify lines 17-20 have exactly 0 occurrences of target weeping keywords."""
        print("\n--- Challenge 1: Character Roster Lines 17-20 Keyword Scan ---")
        lines_17_20 = {
            17: self.lines[16] if len(self.lines) >= 17 else "",
            18: self.lines[17] if len(self.lines) >= 18 else "",
            19: self.lines[18] if len(self.lines) >= 19 else "",
            20: self.lines[19] if len(self.lines) >= 20 else "",
        }

        violations = []
        for line_num, content in lines_17_20.items():
            print(f"Line {line_num}: {content}")
            for kw in TARGET_WEEPING_KEYWORDS:
                if re.search(r'\b' + re.escape(kw) + r'\b', content, re.IGNORECASE):
                    violations.append({
                        "line_num": line_num,
                        "keyword": kw,
                        "content": content
                    })

        self.assertEqual(
            len(violations), 0,
            f"FAIL: Found target weeping keywords in lines 17-20: {violations}"
        )
        print("PASS: Exactly 0 target weeping keywords found in lines 17-20.")

    def test_02_lines_17_to_20_extended_keywords_and_negations(self):
        """Challenge 2: Verify lines 17-20 have 0 extended weeping keywords and 0 negated weeping phrases."""
        print("\n--- Challenge 2: Lines 17-20 Extended Keywords & Negation Purge ---")
        lines_to_check = [
            (17, self.lines[16]),  # Kim Trọng
            (19, self.lines[18]),  # Vương Quan
            (20, self.lines[19]),  # Vương Ông
        ]

        violations = []
        for line_num, content in lines_to_check:
            for kw in EXTENDED_WEEPING_KEYWORDS:
                if kw in content.lower():
                    violations.append({
                        "line_num": line_num,
                        "keyword": kw,
                        "content": content
                    })

        self.assertEqual(
            len(violations), 0,
            f"FAIL: Found extended weeping keywords in male character roster lines 17, 19, 20: {violations}"
        )
        print("PASS: Zero extended weeping keywords or negated weeping phrases in male character entries (lines 17, 19, 20).")

    def test_03_entire_character_roster_male_entries(self):
        """Challenge 3: Verify entire Character Roster (lines 15-26) has 0 male weeping associations."""
        print("\n--- Challenge 3: Entire Character Roster Table Scan (Lines 15-26) ---")
        roster_lines = self.lines[14:26]
        violations = []
        for offset, content in enumerate(roster_lines, 15):
            # Check if this line defines a male character
            is_male_entry = any(m in content for m in ["KIM TRỌNG", "VƯƠNG QUAN", "VƯƠNG ÔNG", "SAI NHA", "MÃ GIÁM SINH"])
            if is_male_entry:
                print(f"Checking male entry Line {offset}: {content[:80]}...")
                for kw in TARGET_WEEPING_KEYWORDS:
                    if kw in content.lower():
                        violations.append({
                            "line_num": offset,
                            "keyword": kw,
                            "content": content
                        })

        self.assertEqual(
            len(violations), 0,
            f"FAIL: Found male weeping keyword associations in Character Roster: {violations}"
        )
        print("PASS: Entire Character Roster male entries confirmed 0 weeping keywords.")

    def test_04_full_screenplay_active_male_weeping_detection(self):
        """Challenge 4: Adversarially audit all 188 shots to confirm 0 active male weeping actions."""
        print("\n--- Challenge 4: Full Screenplay (188 Shots) Active Male Weeping Audit ---")
        active_male_weeping = []

        # Parse shot by shot
        shot_pattern = re.compile(r'#####\s+Shot\s+(\d+):\s+`?(ep01_scene(\d+)_shot(\d+))`?', re.IGNORECASE)
        splits = shot_pattern.split(self.screenplay_text)

        # Iterate over all lines and detect any male character crying action
        current_speaker = None
        for idx, line in enumerate(self.lines, 1):
            line_str = line.strip()
            if not line_str:
                continue

            # Check dialogue speaker
            speaker_match = re.match(r"^\*{0,2}([A-ZÀ-Ỹ\s]+)\*{0,2}:?", line_str)
            if speaker_match:
                speaker = speaker_match.group(1).strip()
                if any(m.upper() in speaker for m in ["KIM TRỌNG", "VƯƠNG QUAN", "VƯƠNG ÔNG"]):
                    current_speaker = speaker
                elif any(f in speaker for f in ["THÚY KIỀU", "THÚY VÂN", "VƯƠNG BÀ", "ĐẠM TIÊN"]):
                    current_speaker = "FEMALE"
                else:
                    current_speaker = "OTHER"

            # Check if current male speaker is weeping in action beat or dialogue
            if current_speaker and current_speaker not in ["FEMALE", "OTHER"]:
                for kw in TARGET_WEEPING_KEYWORDS:
                    if kw in line_str.lower():
                        # Exclude female tears mentioned in the line
                        if any(f in line_str.lower() for f in ["kiều", "nàng", "thúy vân", "vương bà", "mẹ"]):
                            continue
                        # Exclude explicit directive negations
                        if any(neg in line_str.lower() for neg in ["không", "tuyệt đối không", "khô ráo", "0%"]):
                            continue
                        active_male_weeping.append({
                            "line_num": idx,
                            "speaker": current_speaker,
                            "keyword": kw,
                            "text": line_str
                        })

            # Check inline description of male character weeping
            for m in ["Kim Trọng", "Vương Quan", "Vương Ông"]:
                if m in line_str:
                    for kw in TARGET_WEEPING_KEYWORDS:
                        if kw in line_str.lower():
                            # Determine if the tear belongs to female
                            if any(f in line_str.lower() for f in ["kiều", "nàng", "chiếc quạt"]):
                                if "giọt lệ kiều" in line_str.lower() or "giọt nước mắt của kiều" in line_str.lower() or "quạt ngọc" in line_str.lower():
                                    continue
                            # Determine if it's an explicit anti-male-tears directive
                            if any(neg in line_str.lower() for neg in ["không", "tuyệt đối không", "khô ráo", "0%"]):
                                continue
                            active_male_weeping.append({
                                "line_num": idx,
                                "character": m,
                                "keyword": kw,
                                "text": line_str
                            })

        print(f"Active male weeping findings across 188 shots: {len(active_male_weeping)}")
        self.assertEqual(
            len(active_male_weeping), 0,
            f"FAIL: Detected active male weeping in screenplay: {active_male_weeping}"
        )
        print("PASS: Confirmed 0 active male weeping actions or cues across all 188 shots.")

    def test_05_official_helper_find_male_crying_violations(self):
        """Challenge 5: Verify tests.find_male_crying_violations returns exactly 0."""
        print("\n--- Challenge 5: Official Helper find_male_crying_violations ---")
        violations = find_male_crying_violations(self.screenplay_text)
        print(f"Violations count: {len(violations)}")
        for v in violations:
            print(f"  Violation at Line {v['line_num']}: {v['character']} -> {v['text']}")
        self.assertEqual(len(violations), 0, f"Expected 0 violations, got {len(violations)}")
        print("PASS: Official helper confirms 0 violations.")

    def test_06_stoic_positive_indicators_presence(self):
        """Challenge 6: Verify presence of codified positive stoic indicators in lines 17-20."""
        print("\n--- Challenge 6: Stoic Positive Indicators in Lines 17-20 ---")
        line_17 = self.lines[16]
        line_19 = self.lines[18]
        line_20 = self.lines[19]

        # Kim Trọng (Line 17)
        self.assertTrue(
            any(w in line_17.lower() for w in ["khắc kỷ", "kiên định", "nén sâu hơi thở"]),
            "Kim Trọng (Line 17) must have positive stoic indicators"
        )
        # Vương Quan (Line 19)
        self.assertTrue(
            any(w in line_19.lower() for w in ["sắt đá", "kiên cường", "trượng phu"]),
            "Vương Quan (Line 19) must have positive stoic indicators"
        )
        # Vương Ông (Line 20)
        self.assertTrue(
            any(w in line_20.lower() for w in ["khí tiết", "gia trưởng", "kiên cường", "trầm đục đanh thép"]),
            "Vương Ông (Line 20) must have positive stoic indicators"
        )
        print("PASS: Positive feudal stoic indicators verified in all male entries.")


def run_and_export():
    suite = unittest.TestLoader().loadTestsFromTestCase(TestAdversarialMaleWeepingM1)
    runner = unittest.TextTestRunner(verbosity=2)
    result = runner.run(suite)

    report = {
        "tests_run": result.testsRun,
        "was_successful": result.wasSuccessful(),
        "failures_count": len(result.failures),
        "errors_count": len(result.errors),
        "failures": [str(f[1]) for f in result.failures],
        "verdict": "APPROVE" if result.wasSuccessful() else "REQUEST_CHANGES"
    }

    report_path = BASE_DIR / "tests" / "adversarial_male_weeping_m1_results.json"
    with open(report_path, "w", encoding="utf-8") as f:
        json.dump(report, f, indent=2, ensure_ascii=False)

    print(f"\n=======================================================")
    print(f"EMPIRICAL VERDICT: {report['verdict']}")
    print(f"Results exported to {report_path}")
    print(f"=======================================================")

    return 0 if result.wasSuccessful() else 1


if __name__ == "__main__":
    sys.exit(run_and_export())
