"""Independent verification script for Phase 1: Scope, Tech Art, Approvals, and Client Sync.
Executed by victory_auditor_9.
"""
import os
import re
import json
import hashlib
from pathlib import Path
from PIL import Image
import numpy as np

PROJECT_ROOT = Path("c:/Projects/FreeExile")
APPROVED_DRQ_DIR = PROJECT_ROOT / "docs" / "design_requests" / "approved"
INBOX_DRQ_DIR = PROJECT_ROOT / "docs" / "design_requests" / "inbox"
APPROVED_ASSETS_DIR = PROJECT_ROOT / "assets" / "approved"
CLIENT_ASSETS_DIR = PROJECT_ROOT / "client" / "webapp" / "assets"

DRQ_IDS = [
    "DRQ-20261001-CLI-LOADING-SCREEN-ART",
    "DRQ-20261001-CLI-LOGIN-PARALLAX-LAYERS",
    "DRQ-20261001-CLI-TOUCH-CONTROLS-PROMOTION",
    "DRQ-20261001-CLI-WORLD-BACKGROUND-LAYERS",
    "DRQ-20261001-ECO-BAZAAR-TRADE-PANELS",
    "DRQ-20261001-ECO-CRAFTING-ORBS-CATALOG",
    "DRQ-20261001-ECO-CURRENCY-BLOODSTONES",
    "DRQ-20261001-ECO-LOOT-DROP-PARTICLES",
    "DRQ-20261001-NPC-CUTSCENE-STORYBOARD",
    "DRQ-20261001-NPC-FERAL-ELDERS-AVATARS",
    "DRQ-20261001-NPC-QUEST-SCROLL-VARIANTS",
    "DRQ-20261001-SEC-ALERT-BADGES-QUARANTINE",
    "DRQ-20261001-SEC-SHIELD-ACTIVE-ANIMATION",
    "DRQ-20261001-SEC-UI-FORENSIC-WATERMARK",
    "DRQ-20261001-SRV-AGENT-ORB-ACTIVATION-VFX",
    "DRQ-20261001-SRV-AOI-SYNC-TELEMETRY-VISUAL",
    "DRQ-20261001-SRV-HARVEST-REPORT-OVERLAY",
    "DRQ-20261001-SYS-CRAFTING-STATION-UI",
    "DRQ-20261001-SYS-HIDEOUT-SAFEHAVEN-PROPS",
    "DRQ-20261001-SYS-MAP-DEVICE-ARENA",
    "DRQ-20261001-SYS-PASSIVE-TREE-NODES",
]

def is_power_of_two(n: int) -> bool:
    return n > 0 and (n & (n - 1)) == 0

def sha256_file(path: Path) -> str:
    h = hashlib.sha256()
    with open(path, "rb") as f:
        while chunk := f.read(65536):
            h.update(chunk)
    return h.hexdigest()

def main():
    print(f"=== Starting Independent Forensic Verification ===")
    results = {
        "drq_count": len(DRQ_IDS),
        "drq_checks": [],
        "total_deliverables": 0,
        "png_deliverables": 0,
        "normal_map_deliverables": 0,
        "emissive_deliverables": 0,
        "metal_shader_deliverables": 0,
        "json_manifest_deliverables": 0,
        "client_sync_matches": 0,
        "client_sync_failures": [],
        "errors": []
    }

    # 1. Check DRQs and 2-tier approval
    for drq_id in DRQ_IDS:
        drq_file = APPROVED_DRQ_DIR / f"{drq_id}.md"
        if not drq_file.exists():
            results["errors"].append(f"DRQ file missing: {drq_file}")
            continue

        content = drq_file.read_text(encoding="utf-8")
        
        # Check Stage 1 and Stage 2 approval signatures
        stage1_pass = bool(re.search(r"(?:Stage 1|Cấp 1).*?(?:PASS|APPROVED)", content, re.IGNORECASE))
        stage2_pass = bool(re.search(r"(?:Stage 2|Cấp 2).*?(?:PASS|APPROVED)", content, re.IGNORECASE))
        
        # Check Section 4 Deliverables
        m = re.search(r"## 4\..*?(?:Deliverables|SẢN PHẨM ĐẦU RA).*?(?=## 5|\Z)", content, re.DOTALL | re.IGNORECASE)
        if not m:
            results["errors"].append(f"Section 4 Deliverables missing in {drq_id}")
            deliverables = []
        else:
            deliverables_text = m.group(0)
            # Find bullet items with backticks or filenames
            items = re.findall(r"-\s*\[[ xX]\]\s*`?([a-zA-Z0-9_\-\.\/]+)`?|-\s*`([a-zA-Z0-9_\-\.\/]+)`", deliverables_text)
            deliverables = []
            for it in items:
                fn = (it[0] or it[1]).strip()
                if any(fn.endswith(ext) for ext in [".png", ".metal", ".json"]):
                    deliverables.append(fn)

        results["drq_checks"].append({
            "drq_id": drq_id,
            "stage1_pass": stage1_pass,
            "stage2_pass": stage2_pass,
            "deliverable_count": len(deliverables),
            "deliverables": deliverables
        })

    print(f"Verified {len(results['drq_checks'])} DRQ markdown files.")
    
    # 2. Check Assets in assets/approved/<DRQ-ID>/
    all_deliverables_found = []
    
    for check in results["drq_checks"]:
        drq_id = check["drq_id"]
        drq_dir = APPROVED_ASSETS_DIR / drq_id
        if not drq_dir.exists() or not drq_dir.is_dir():
            results["errors"].append(f"Approved asset directory missing: {drq_dir}")
            continue

        files_in_dir = list(drq_dir.iterdir())
        for f in files_in_dir:
            if f.is_file():
                results["total_deliverables"] += 1
                fname = f.name
                fsize = f.stat().st_size
                if fsize == 0:
                    results["errors"].append(f"Empty asset file: {f}")
                
                # PNG checks
                if fname.endswith(".png"):
                    results["png_deliverables"] += 1
                    try:
                        with Image.open(f) as img:
                            w, h = img.size
                            mode = img.mode
                            if not (is_power_of_two(w) and is_power_of_two(h)):
                                results["errors"].append(f"Non-power-of-2 dimensions {w}x{h} in {f}")
                            
                            # Normal map check
                            if fname.endswith("_normal.png"):
                                results["normal_map_deliverables"] += 1
                                arr = np.array(img.convert("RGB"))
                                b_mean = float(np.mean(arr[:, :, 2]))
                                if b_mean < 128.0:
                                    results["errors"].append(f"Normal map Blue channel mean < 128 ({b_mean:.2f}) in {f}")
                            
                            # Emissive mask check
                            if fname.endswith("_emissive.png"):
                                results["emissive_deliverables"] += 1
                    except Exception as e:
                        results["errors"].append(f"Failed decoding image {f}: {e}")

                elif fname.endswith(".metal"):
                    results["metal_shader_deliverables"] += 1
                    content = f.read_text(encoding="utf-8")
                    if "#include <metal_stdlib>" not in content:
                        results["errors"].append(f"Metal shader {f} missing standard MSL include")

                elif fname.endswith(".json"):
                    results["json_manifest_deliverables"] += 1
                    try:
                        with open(f, "r", encoding="utf-8") as jf:
                            json.load(jf)
                    except Exception as e:
                        results["errors"].append(f"Failed parsing JSON manifest {f}: {e}")

                all_deliverables_found.append((drq_id, f))

    # 3. Check client webapp synchronization
    # Locate where each file was copied in client/webapp/assets
    for drq_id, approved_file in all_deliverables_found:
        fname = approved_file.name
        # Search for this file under client/webapp/assets/
        matched_client_files = list(CLIENT_ASSETS_DIR.rglob(fname))
        if not matched_client_files:
            results["client_sync_failures"].append(f"File {fname} from {drq_id} not found in {CLIENT_ASSETS_DIR}")
        else:
            approved_hash = sha256_file(approved_file)
            matched = False
            for client_file in matched_client_files:
                if sha256_file(client_file) == approved_hash:
                    matched = True
                    results["client_sync_matches"] += 1
                    break
            if not matched:
                results["client_sync_failures"].append(
                    f"Hash mismatch for {fname}: approved {approved_hash} vs client {matched_client_files[0]} ({sha256_file(matched_client_files[0])})"
                )

    print(f"Total deliverables inspected: {results['total_deliverables']}")
    print(f"  PNGs: {results['png_deliverables']}")
    print(f"  Normal maps: {results['normal_map_deliverables']}")
    print(f"  Emissive masks: {results['emissive_deliverables']}")
    print(f"  Metal shaders: {results['metal_shader_deliverables']}")
    print(f"  JSON manifests: {results['json_manifest_deliverables']}")
    print(f"Client sync matches: {results['client_sync_matches']}")
    print(f"Client sync failures: {len(results['client_sync_failures'])}")
    print(f"Errors encountered: {len(results['errors'])}")
    
    output_path = Path("c:/Projects/FreeExile/.agents/teamwork/victory_auditor_9/phase1_results.json")
    with open(output_path, "w", encoding="utf-8") as out:
        json.dump(results, out, indent=2)
    print(f"Saved results to {output_path}")

if __name__ == "__main__":
    main()
