#!/usr/bin/env python3
"""
Glitch pattern definitions for 3D world anomaly detection.

Defines known visual artifact categories commonly found in 3D web worlds,
particularly The Matrix environments. Each pattern includes detection
heuristics and severity ratings.
"""

from dataclasses import dataclass, field
from enum import Enum
from typing import Optional


class GlitchSeverity(Enum):
    CRITICAL = "critical"
    HIGH = "high"
    MEDIUM = "medium"
    LOW = "low"
    INFO = "info"


class GlitchCategory(Enum):
    FLOATING_ASSETS = "floating_assets"
    Z_FIGHTING = "z_fighting"
    MISSING_TEXTURES = "missing_textures"
    CLIPPING = "clipping"
    BROKEN_NORMALS = "broken_normals"
    SHADOW_ARTIFACTS = "shadow_artifacts"
    LIGHTMAP_ERRORS = "lightmap_errors"
    LOD_POPPING = "lod_popping"
    WATER_REFLECTION = "water_reflection"
    SKYBOX_SEAM = "skybox_seam"


@dataclass
class GlitchPattern:
    """Definition of a known glitch pattern with detection parameters."""
    category: GlitchCategory
    name: str
    description: str
    severity: GlitchSeverity
    detection_prompts: list[str]
    visual_indicators: list[str]
    confidence_threshold: float = 0.6

    def to_dict(self) -> dict:
        return {
            "category": self.category.value,
            "name": self.name,
            "description": self.description,
            "severity": self.severity.value,
            "detection_prompts": self.detection_prompts,
            "visual_indicators": self.visual_indicators,
            "confidence_threshold": self.confidence_threshold,
        }


# Known glitch patterns for Matrix 3D world scanning
MATRIX_GLITCH_PATTERNS: list[GlitchPattern] = [
    GlitchPattern(
        category=GlitchCategory.FLOATING_ASSETS,
        name="Floating Object",
        description="Object not properly grounded or anchored to the scene geometry. "
                    "Common in procedurally placed assets or after physics desync.",
        severity=GlitchSeverity.HIGH,
        detection_prompts=[
            "Identify any objects that appear to float above the ground without support.",
            "Look for furniture, props, or geometry suspended in mid-air with no visible attachment.",
            "Check for objects whose shadows do not align with the surface below them.",
        ],
        visual_indicators=[
            "gap between object base and surface",
            "shadow detached from object",
            "object hovering with no structural support",
        ],
        confidence_threshold=0.65,
    ),
    GlitchPattern(
        category=GlitchCategory.Z_FIGHTING,
        name="Z-Fighting Flicker",
        description="Two coplanar surfaces competing for depth priority, causing "
                    "visible flickering or shimmering textures.",
        severity=GlitchSeverity.MEDIUM,
        detection_prompts=[
            "Look for surfaces that appear to shimmer, flicker, or show mixed textures.",
            "Identify areas where two textures seem to overlap and compete for visibility.",
            "Check walls, floors, or objects for surface noise or pattern interference.",
        ],
        visual_indicators=[
            "shimmering surface",
            "texture flicker between two patterns",
            "noisy flat surfaces",
            "moire-like patterns on planar geometry",
        ],
        confidence_threshold=0.55,
    ),
    GlitchPattern(
        category=GlitchCategory.MISSING_TEXTURES,
        name="Missing or Placeholder Texture",
        description="A surface rendered with a fallback checkerboard, solid magenta, "
                    "or the default engine placeholder texture.",
        severity=GlitchSeverity.CRITICAL,
        detection_prompts=[
            "Look for bright magenta, checkerboard, or solid-color surfaces that look out of place.",
            "Identify any surfaces that appear as flat untextured colors inconsistent with the scene.",
            "Check for black, white, or magenta patches where detailed textures should be.",
        ],
        visual_indicators=[
            "magenta/pink solid color surface",
            "checkerboard pattern",
            "flat single-color geometry",
            "UV-debug texture visible",
        ],
        confidence_threshold=0.7,
    ),
    GlitchPattern(
        category=GlitchCategory.CLIPPING,
        name="Geometry Clipping",
        description="Objects passing through each other or intersecting in physically "
                    "impossible ways due to collision mesh errors.",
        severity=GlitchSeverity.HIGH,
        detection_prompts=[
            "Look for objects that visibly pass through other objects (walls, floors, furniture).",
            "Identify characters or props embedded inside geometry where they should not be.",
            "Check for intersecting meshes where solid objects overlap unnaturally.",
        ],
        visual_indicators=[
            "object passing through wall or floor",
            "embedded geometry",
            "overlapping solid meshes",
            "character limb inside furniture",
        ],
        confidence_threshold=0.6,
    ),
    GlitchPattern(
        category=GlitchCategory.BROKEN_NORMALS,
        name="Broken Surface Normals",
        description="Inverted or incorrect surface normals causing faces to appear "
                    "inside-out, invisible from certain angles, or lit incorrectly.",
        severity=GlitchSeverity.MEDIUM,
        detection_prompts=[
            "Look for surfaces that appear dark or black on one side while lit on the other.",
            "Identify objects that seem to vanish when viewed from certain angles.",
            "Check for inverted shading where lit areas should be in shadow.",
        ],
        visual_indicators=[
            "dark/unlit face on otherwise lit model",
            "invisible surface from one direction",
            "inverted shadow gradient",
            "inside-out appearance",
        ],
        confidence_threshold=0.5,
    ),
    GlitchPattern(
        category=GlitchCategory.SHADOW_ARTIFACTS,
        name="Shadow Artifact",
        description="Broken, detached, or incorrectly rendered shadows that do not "
                    "match the casting geometry or scene lighting.",
        severity=GlitchSeverity.LOW,
        detection_prompts=[
            "Look for shadows that do not match the shape of nearby objects.",
            "Identify shadow acne: banding or striped patterns on surfaces.",
            "Check for floating shadows detached from any visible caster.",
        ],
        visual_indicators=[
            "shadow shape mismatch",
            "shadow acne bands",
            "detached floating shadow",
            "Peter Panning (shadow offset from base)",
        ],
        confidence_threshold=0.5,
    ),
    GlitchPattern(
        category=GlitchCategory.LOD_POPPING,
        name="LOD Transition Pop",
        description="Visible pop-in when level-of-detail models switch abruptly, "
                    "causing geometry or textures to change suddenly.",
        severity=GlitchSeverity.LOW,
        detection_prompts=[
            "Look for areas where mesh detail changes abruptly at visible boundaries.",
            "Identify objects that appear to morph or shift geometry suddenly.",
            "Check for texture resolution changes that create visible seams.",
        ],
        visual_indicators=[
            "visible mesh simplification boundary",
            "texture resolution jump",
            "geometry pop-in artifacts",
        ],
        confidence_threshold=0.45,
    ),
    GlitchPattern(
        category=GlitchCategory.LIGHTMAP_ERRORS,
        name="Lightmap Baking Error",
        description="Incorrect or missing baked lighting causing dark spots, light "
                    "leaks, or mismatched illumination on static geometry.",
        severity=GlitchSeverity.MEDIUM,
        detection_prompts=[
            "Look for unusually dark patches on walls or ceilings that should be lit.",
            "Identify bright light leaks through solid geometry seams.",
            "Check for mismatched lighting between adjacent surfaces.",
        ],
        visual_indicators=[
            "dark splotch on lit surface",
            "bright line at geometry seam",
            "lighting discontinuity between adjacent faces",
        ],
        confidence_threshold=0.5,
    ),
    GlitchPattern(
        category=GlitchCategory.WATER_REFLECTION,
        name="Water/Reflection Error",
        description="Incorrect reflections, missing water surfaces, or broken "
                    "reflection probe assignments.",
        severity=GlitchSeverity.MEDIUM,
        detection_prompts=[
            "Look for reflections that do not match the surrounding environment.",
            "Identify water surfaces that appear solid or incorrectly rendered.",
            "Check for mirror surfaces showing wrong scene geometry.",
        ],
        visual_indicators=[
            "reflection mismatch",
            "solid water surface",
            "incorrect environment map",
        ],
        confidence_threshold=0.5,
    ),
    GlitchPattern(
        category=GlitchCategory.SKYBOX_SEAM,
        name="Skybox Seam",
        description="Visible seams or color mismatches at the edges of skybox cubemap faces.",
        severity=GlitchSeverity.LOW,
        detection_prompts=[
            "Look at the edges of the sky for visible seams or color shifts.",
            "Identify discontinuities where skybox faces meet.",
            "Check for texture stretching at skybox corners.",
        ],
        visual_indicators=[
            "visible line in sky",
            "color discontinuity at sky edge",
            "sky texture seam",
        ],
        confidence_threshold=0.45,
    ),
]


def get_patterns_by_severity(min_severity: GlitchSeverity) -> list[GlitchPattern]:
    """Return patterns at or above the given severity level."""
    severity_order = [
        GlitchSeverity.INFO,
        GlitchSeverity.LOW,
        GlitchSeverity.MEDIUM,
        GlitchSeverity.HIGH,
        GlitchSeverity.CRITICAL,
    ]
    min_idx = severity_order.index(min_severity)
    return [p for p in MATRIX_GLITCH_PATTERNS if severity_order.index(p.severity) >= min_idx]


def get_pattern_by_category(category: GlitchCategory) -> Optional[GlitchPattern]:
    """Return the pattern definition for a specific category."""
    for p in MATRIX_GLITCH_PATTERNS:
        if p.category == category:
            return p
    return None


def build_vision_prompt(patterns: list[GlitchPattern] | None = None) -> str:
    """Build a composite vision analysis prompt from pattern definitions."""
    if patterns is None:
        patterns = MATRIX_GLITCH_PATTERNS

    sections = []
    for p in patterns:
        prompt_text = " ".join(p.detection_prompts)
        indicators = ", ".join(p.visual_indicators)
        sections.append(
            f"[{p.category.value.upper()}] {p.name} (severity: {p.severity.value})\n"
            f"  {p.description}\n"
            f"  Look for: {prompt_text}\n"
            f"  Visual indicators: {indicators}"
        )

    return (
        "Analyze this 3D world screenshot for visual glitches and artifacts. "
        "For each detected issue, report the category, description of what you see, "
        "approximate location in the image (x%, y%), and confidence (0.0-1.0).\n\n"
        "Known glitch patterns to check:\n\n" + "\n\n".join(sections)
    )



def get_threejs_patterns():
    """Get all glitch patterns (Three.js categories are all categories)."""
    return MATRIX_GLITCH_PATTERNS


if __name__ == "__main__":
    import json
    print(f"Loaded {len(MATRIX_GLITCH_PATTERNS)} glitch patterns:\n")
    for p in MATRIX_GLITCH_PATTERNS:
        print(f"  [{p.severity.value:8s}] {p.category.value}: {p.name}")
    print(f"\nVision prompt preview:\n{build_vision_prompt()[:500]}...")
