#!/usr/bin/env python3
"""Valheim World POI Database Builder
Parses locations.json into a queryable SQLite database with spatial support.
"""
import json, sqlite3, re, sys
from collections import Counter

DB_PATH = "/tmp/valheim_poi.db"
JSON_PATH = "/tmp/valheim_locations.json"

# ── Parse position strings like "(1.8, 81.4, 0.0)" ──
def parse_pos(s):
    """Returns (x, y_height, z) — x/z are map coords, y is altitude."""
    m = re.match(r'\(?(-?[\d.]+),\s*(-?[\d.]+),\s*(-?[\d.]+)\)?', str(s))
    if m:
        return float(m.group(1)), float(m.group(2)), float(m.group(3))
    return None, None, None

def classify_prefab(name):
    """Classify a prefab into a category for querying."""
    categories = {
        'boss': ['Eikthyrnir', 'Bonemass', 'GDKing', 'GoblinKing', 'Moder', 'Yagluth', 'SeekerQueen'],
        'dungeon': ['Crypt', 'SunkenCrypt', 'Cave', 'DvergrTown', 'Mistlands_Dungeon'],
        'vegvisir': ['Vegvisir'],
        'altar': ['OfferingPlace', 'Runestone', 'StoneHenge'],
        'vendor': ['Vendor_BlackForest', 'Haldor', 'Hildir'],
        'structure': ['Castle', 'Tower', 'Ruin', 'Fortress', 'Camp'],
        'resource': ['TarPit', 'Obsidian', 'Silver', 'Copper', 'Tin', 'DragonEgg', 'Mistlands_Guards'],
        'spawner': ['Spawner', 'SpawnArea'],
        'point_of_interest': ['StartTemple', 'FulingVillage', 'VikingBroad', 'StoneBridge'],
    }
    for cat, patterns in categories.items():
        for p in patterns:
            if p.lower() in name.lower():
                return cat
    return 'other'

def create_db(conn):
    c = conn.cursor()
    c.executescript("""
        DROP TABLE IF EXISTS locations;
        DROP TABLE IF EXISTS important_contents;
        DROP TABLE IF EXISTS random_contents;
        DROP TABLE IF EXISTS dungeon_components;
        DROP TABLE IF EXISTS prefab_categories;
        
        CREATE TABLE locations (
            id INTEGER PRIMARY KEY,
            prefab_name TEXT NOT NULL,
            category TEXT NOT NULL,
            pos_x REAL,
            pos_y REAL,   -- altitude/height
            pos_z REAL,   -- map depth
            has_dungeon INTEGER DEFAULT 0,
            has_important INTEGER DEFAULT 0,
            has_random INTEGER DEFAULT 0
        );
        
        CREATE TABLE important_contents (
            id INTEGER PRIMARY KEY,
            location_id INTEGER NOT NULL,
            friendly_name TEXT,
            count INTEGER,
            icon TEXT,
            FOREIGN KEY (location_id) REFERENCES locations(id)
        );
        
        CREATE TABLE random_contents (
            id INTEGER PRIMARY KEY,
            location_id INTEGER NOT NULL,
            type TEXT,
            parent TEXT,
            name TEXT,
            interior INTEGER,
            FOREIGN KEY (location_id) REFERENCES locations(id)
        );
        
        CREATE TABLE dungeon_components (
            id INTEGER PRIMARY KEY,
            location_id INTEGER NOT NULL,
            delta_x REAL,
            delta_y REAL,
            rotation_y REAL,
            parent_type TEXT,
            parent_name TEXT,
            FOREIGN KEY (location_id) REFERENCES locations(id)
        );
        
        CREATE INDEX idx_locations_prefab ON locations(prefab_name);
        CREATE INDEX idx_locations_category ON locations(category);
        CREATE INDEX idx_locations_pos ON locations(pos_x, pos_z);
        CREATE INDEX idx_important_name ON important_contents(friendly_name);
        CREATE INDEX idx_random_type ON random_contents(type, parent);
    """)
    conn.commit()

def parse_and_insert(conn):
    c = conn.cursor()
    loc_id = 0
    imp_id = 0
    rnd_id = 0
    cmp_id = 0
    
    prefab_counter = Counter()
    category_counter = Counter()
    imp_counter = Counter()
    
    print("Parsing locations.json...")
    with open(JSON_PATH, 'r', encoding='utf-8') as f:
        data = json.load(f)
    
    total = len(data)
    print(f"Total locations: {total}")
    
    for i, loc in enumerate(data):
        prefab = loc.get('PrefabName', 'Unknown')
        pos_str = loc.get('Position', '')
        x, y, z = parse_pos(pos_str)
        category = classify_prefab(prefab)
        
        prefab_counter[prefab] += 1
        category_counter[category] += 1
        
        has_dungeon = 1 if 'DungeonComponents' in loc and loc['DungeonComponents'] else 0
        has_important = 1 if 'ImportantContents' in loc and loc['ImportantContents'] else 0
        has_random = 1 if 'RandomContents' in loc and loc['RandomContents'] else 0
        
        loc_id += 1
        c.execute("""
            INSERT INTO locations (id, prefab_name, category, pos_x, pos_y, pos_z,
                                   has_dungeon, has_important, has_random)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
        """, (loc_id, prefab, category, x, y, z, has_dungeon, has_important, has_random))
        
        # Important contents
        for ic in loc.get('ImportantContents', []):
            imp_id += 1
            friendly = ic.get('FriendlyName', '')
            count = ic.get('Count', 1)
            icon = ic.get('Icon', '')
            imp_counter[friendly] += count
            c.execute("""
                INSERT INTO important_contents (id, location_id, friendly_name, count, icon)
                VALUES (?, ?, ?, ?, ?)
            """, (imp_id, loc_id, friendly, count, icon))
        
        # Random contents  
        for rc in loc.get('RandomContents', []):
            rnd_id += 1
            c.execute("""
                INSERT INTO random_contents (id, location_id, type, parent, name, interior)
                VALUES (?, ?, ?, ?, ?, ?)
            """, (rnd_id, loc_id, rc.get('Type',''), rc.get('Parent',''), 
                  rc.get('Name',''), rc.get('Interior',0)))
        
        # Dungeon components
        for dc in loc.get('DungeonComponents', []):
            cmp_id += 1
            ik = dc.get('ImageKey', {})
            c.execute("""
                INSERT INTO dungeon_components (id, location_id, delta_x, delta_y, 
                                                  rotation_y, parent_type, parent_name)
                VALUES (?, ?, ?, ?, ?, ?, ?)
            """, (cmp_id, loc_id, dc.get('DeltaX',0), dc.get('DeltaY',0),
                  dc.get('RotationY',0), ik.get('Type',''), ik.get('Parent','')))
        
        if (i + 1) % 5000 == 0:
            print(f"  Processed {i+1}/{total}...")
            conn.commit()
    
    conn.commit()
    
    print("\n=== Summary ===")
    print(f"Locations: {loc_id}")
    print(f"Important contents: {imp_id}")
    print(f"Random contents: {rnd_id}")
    print(f"Dungeon components: {cmp_id}")
    
    print("\n--- By Category ---")
    for cat, cnt in sorted(category_counter.items(), key=lambda x: -x[1]):
        print(f"  {cat}: {cnt}")
    
    print("\n--- Top 20 Prefabs ---")
    for prefab, cnt in prefab_counter.most_common(20):
        print(f"  {prefab}: {cnt}")
    
    print("\n--- Top 20 Important Contents ---")
    for name, cnt in imp_counter.most_common(20):
        print(f"  {name}: {cnt}")
    
    return conn

def demo_queries(conn):
    c = conn.cursor()
    print("\n" + "="*60)
    print("DEMO QUERIES")
    print("="*60)
    
    # 1. Boss locations
    print("\n--- Boss Altars ---")
    for row in c.execute("""
        SELECT prefab_name, pos_x, pos_z FROM locations 
        WHERE category='boss' ORDER BY prefab_name
    """):
        print(f"  {row[0]}: ({row[1]:.0f}, {row[2]:.0f})")
    
    # 2. Tar pits
    print("\n--- Tar Pits ---")
    for row in c.execute("""
        SELECT pos_x, pos_z FROM locations WHERE prefab_name LIKE '%TarPit%'
    """):
        print(f"  Tar Pit at ({row[0]:.0f}, {row[1]:.0f})")
    
    # 3. Surtling cores in dungeons
    print("\n--- Surtling Core Locations ---")
    for row in c.execute("""
        SELECT l.prefab_name, l.pos_x, l.pos_z, SUM(ic.count) as total
        FROM locations l JOIN important_contents ic ON l.id = ic.location_id
        WHERE ic.friendly_name LIKE '%SurtlingCore%'
        GROUP BY l.id ORDER BY total DESC LIMIT 10
    """):
        print(f"  {row[0]} @ ({row[1]:.0f},{row[2]:.0f}): {row[3]} cores")
    
    # 4. Vegvisirs
    print("\n--- Vegvisirs (Boss Hint Stones) ---")
    for row in c.execute("""
        SELECT ic.friendly_name, l.pos_x, l.pos_z
        FROM locations l JOIN important_contents ic ON l.id = ic.location_id
        WHERE ic.friendly_name LIKE '%Vegvisir%'
    """):
        print(f"  {row[0]} at ({row[1]:.0f}, {row[2]:.0f})")
    
    # 5. Tar pit density - find clusters
    print("\n--- Tar Pit Cluster Analysis ---")
    rows = c.execute("""
        SELECT pos_x, pos_z FROM locations WHERE prefab_name LIKE '%TarPit%'
    """).fetchall()
    if rows:
        # Find highest density zone (grid-based)
        grid = {}
        grid_size = 1000  # 1000 unit cells
        for x, z in rows:
            gx, gz = int(x // grid_size), int(z // grid_size)
            grid[(gx, gz)] = grid.get((gx, gz), 0) + 1
        top = sorted(grid.items(), key=lambda x: -x[1])[:5]
        for (gx, gz), cnt in top:
            center_x = gx * grid_size + grid_size // 2
            center_z = gz * grid_size + grid_size // 2
            print(f"  Zone ({center_x}, {center_z}): {cnt} tar pits in {grid_size}u radius")

if __name__ == '__main__':
    import os
    if os.path.exists(DB_PATH):
        os.remove(DB_PATH)
    
    conn = sqlite3.connect(DB_PATH)
    conn.execute("PRAGMA journal_mode=WAL")
    conn.execute("PRAGMA synchronous=NORMAL")
    
    create_db(conn)
    parse_and_insert(conn)
    demo_queries(conn)
    
    conn.close()
    print(f"\nDatabase saved to {DB_PATH}")
    print(f"Size: {os.path.getsize(DB_PATH) / 1024 / 1024:.1f} MB")
