#!/usr/bin/env python3
"""
Pre-flight Game Design Matrix & Cross-Cutting Integrity Linter.
Verifies that all Quests, Zones, Acts, NPCs, Monsters, Weapons, Skills, and Progression
curves are 100% synchronized with zero DAG cycles, zero broken foreign keys, and zero drift
across Code Catalogs, SQLite Database, and Markdown Documentation (wiki/vi/).

Exit code:
  0 = PASS (Integrity verified, ready for dev/commit)
  1 = FAIL (Cross-system drift or violations detected)
"""

from __future__ import annotations
import sys
import os
import re
import argparse
from typing import List, Set, Tuple

if hasattr(sys.stdout, "reconfigure"):
    sys.stdout.reconfigure(encoding="utf-8")

# Add project root to sys.path
PROJECT_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
sys.path.insert(0, PROJECT_ROOT)

from server.world.game_design_matrix_service import GameDesignMatrixService


def verify_docs_synchronization(service: GameDesignMatrixService) -> Tuple[List[str], List[str]]:
    """Verifies that Quests in Database match Quests documented in wiki/vi/ specs."""
    violations: List[str] = []
    warnings: List[str] = []

    wiki_quest_file = os.path.join(PROJECT_ROOT, "wiki", "vi", "QUESTS_AND_MILESTONES_SPECS.md")
    if not os.path.exists(wiki_quest_file):
        warnings.append(f"Wiki quest specs file not found at: {wiki_quest_file}")
        return violations, warnings

    with open(wiki_quest_file, "r", encoding="utf-8") as f:
        content = f.read()

    # Extract all backtick quest IDs
    doc_quest_ids = set(re.findall(r"`(quest_[a-z0-9_]+)`", content))

    with service._get_connection() as conn:
        cur = conn.cursor()
        cur.execute("SELECT quest_id, title FROM quests")
        db_quests = {r["quest_id"]: r["title"] for r in cur.fetchall()}

    # Check: every DB quest must be in doc
    missing_in_doc = []
    for qid in db_quests:
        if qid not in doc_quest_ids:
            missing_in_doc.append(qid)

    if missing_in_doc:
        violations.append(
            f"Doc Drift: {len(missing_in_doc)} quests in Database are MISSING from wiki specs: "
            f"{', '.join(missing_in_doc)}"
        )

    return violations, warnings


def main() -> int:
    parser = argparse.ArgumentParser(description="Audit and synchronize Game Design Matrix with Code and Docs.")
    parser.add_argument("--sync", action="store_true", default=True, help="Automatically re-sync database from code catalogs.")
    parser.add_argument("--no-sync", dest="sync", action="store_false", help="Do not re-sync database, only validate existing state.")
    parser.add_argument("--check-docs", action="store_true", default=True, help="Verify synchronization between Database and wiki docs.")
    args = parser.parse_args()

    service = GameDesignMatrixService()
    if args.sync:
        service.seed_canonical_data(force=True)

    report = service.validate_game_design_integrity()

    party_scalings = service.get_all_party_scalings()
    loot_modes = service.get_all_loot_allocation_modes()
    teleport_cfgs = service.get_all_teleport_configs()
    quarantine_rules = service.get_all_portal_quarantine_rules()

    doc_violations: List[str] = []
    doc_warnings: List[str] = []
    if args.check_docs:
        doc_violations, doc_warnings = verify_docs_synchronization(service)

    service.close()

    matrix_violations: List[str] = []
    if len(party_scalings) != 6:
        matrix_violations.append(f"Party Scaling: expected 6 sizes, found {len(party_scalings)}")
    for i in range(len(party_scalings) - 1):
        curr, nxt = party_scalings[i], party_scalings[i + 1]
        if nxt.hp_multiplier < curr.hp_multiplier or nxt.exp_bonus_pct < curr.exp_bonus_pct or nxt.item_quantity_bonus_pct < curr.item_quantity_bonus_pct:
            matrix_violations.append(f"Party Scaling: non-monotonic scaling between size {curr.party_size} and {nxt.party_size}")
    if not any(m.mode_id == "SHORT" and m.timeout_seconds == 5.0 for m in loot_modes):
        matrix_violations.append("Loot Allocation: SHORT mode with 5.0s timeout is required")
    if not any(t.cast_time_seconds == 3.5 and t.cancel_on_movement and t.cancel_on_damage for t in teleport_cfgs):
        matrix_violations.append("Teleport Config: 3.5s cast with cancel_on_movement/damage required")
    if not any(q.boss_lockout and q.secret_chamber_lockout and q.max_portals == 6 for q in quarantine_rules):
        matrix_violations.append("Portal Quarantine: boss_lockout=True, secret_chamber_lockout=True, max_portals=6 required")

    total_violations = list(report.violations) + matrix_violations + doc_violations
    total_warnings = list(report.warnings) + doc_warnings
    is_fully_synced = (len(total_violations) == 0)

    print("=" * 70)
    print(" FREEEXILE GAME DESIGN MATRIX & CROSS-SYSTEM INTEGRITY AUDIT ")
    print("=" * 70)
    print(f"Status:               {'[PASS]' if is_fully_synced else '[FAIL]'}")
    print(f"Auto-Sync Mode:       {'ENABLED (Catalogs -> DB)' if args.sync else 'DISABLED'}")
    print(f"Docs Consistency:     {'VERIFIED (DB <-> wiki/vi/)' if args.check_docs else 'SKIPPED'}")
    print(f"Story Acts:           {report.total_acts}")
    print(f"World Zones:          {report.total_zones}")
    print(f"NPCs:                 {report.total_npcs}")
    print(f"Quests & Milestones:  {report.total_quests}")
    print(f"Monster Archetypes:   {report.total_monsters}")
    print(f"Active Skills:        {report.total_skills}")
    print(f"Base Weapons:         {report.total_weapons}")
    print(f"15-Tier Affixes:      {report.total_affixes}")
    print(f"Cross-Relationships:  {report.total_relations}")
    print(f"Party Scaling Levels: {len(party_scalings)} (Sizes 1..6, Monotonic Verified)")
    print(f"Loot Allocation Modes:{len(loot_modes)} (Permanent, Short 5s, Free-For-All)")
    print(f"Teleport Configs:     {len(teleport_cfgs)} (Cast 3.5s, Cancel on Move/Dmg)")
    print(f"Quarantine Rules:     {len(quarantine_rules)} (Boss & Secret Lockout)")
    print("-" * 70)

    if total_warnings:
        print(f"[WARN] DESIGN WARNINGS ({len(total_warnings)}):")
        for w in total_warnings:
            print(f"   * {w}")
        print("-" * 70)

    if total_violations:
        print(f"[ERROR] INTEGRITY & SYNC VIOLATIONS ({len(total_violations)}):")
        for v in total_violations:
            print(f"   ! {v}")
        print("=" * 70)
        print("FAILED: Cross-system drift detected between Code, DB, or Docs.")
        return 1

    print("=" * 70)
    print("SUCCESS: Code, Central Database, and Documentation are 100% IN SYNC.")
    return 0


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