#!/usr/bin/env python3
"""Tag Disney assets with their park/resort code and update display names.

Step 1: Map each location name → disney_park code + display name
Step 2: Update assets (disney_park + append display name)
Step 3: Update locations (add disney_park column if missing, set values)

Usage:
    python scripts/tag_disney_properties.py          # dry-run
    python scripts/tag_disney_properties.py --apply  # actually update the DB
"""

import argparse
import sqlite3
import sys
import os

# ── Disney property mapping ──────────────────────────────────────────────────
# Each location name pattern is mapped to (disney_park_code, display_name, emoji)
# Patterns are checked as case-insensitive substring matches, ordered by priority.

PARK_MAPPING = [
    # --- Resorts (specific before generic! order matters) ---
    ("D-All Star Movie",    "resort",  "🏨 All Star Movies"),
    ("D-All Star Music",    "resort",  "🏨 All Star Music"),
    ("D-All Star Sports",   "resort",  "🏨 All Star Sports"),
    ("D-ALL STAR",          "resort",  "🏨 All Star"),
    ("ART OF ANIMATION",    "resort",  "🏨 Art of Animation"),
    ("D-ART OF ANIMATION",  "resort",  "🏨 Art of Animation"),
    ("Animal Kngdm LODGE",  "resort",  "🏨 Animal Kingdom Lodge"),
    ("Animal Kngdm Lodge",  "resort",  "🏨 Animal Kingdom Lodge"),
    ("BAY LAKE TOWER",      "resort",  "🏨 Bay Lake Tower"),
    ("D-BAY LAKE TOWER",    "resort",  "🏨 Bay Lake Tower"),
    ("BLIZZARD BEACH",      "resort",  "🏨 Blizzard Beach"),
    ("D-BLIZZARD BEACH",    "resort",  "🏨 Blizzard Beach"),
    ("Boardwalk CAST",      "resort",  "🏨 Boardwalk"),
    ("Boardwalk GUEST",     "resort",  "🏨 Boardwalk"),
    ("D-Boardwalk",         "resort",  "🏨 Boardwalk"),
    ("CARIBBEAN BEACH",     "resort",  "🏨 Caribbean Beach"),
    ("D-CARIBBEAN BEACH",   "resort",  "🏨 Caribbean Beach"),
    ("D-Caribbean Beach",   "resort",  "🏨 Caribbean Beach"),
    ("CORONADO SPRINGS",    "resort",  "🏨 Coronado Springs"),
    ("D-CORONADO SPRINGS",  "resort",  "🏨 Coronado Springs"),
    ("ContemporaryHotel",   "resort",  "🏨 Contemporary"),
    ("D-ContemporaryHotel", "resort",  "🏨 Contemporary"),
    ("FANTASIA GOLF",       "resort",  "🏨 Fantasia Golf"),
    ("D-FANTASIA GOLF",     "resort",  "🏨 Fantasia Golf"),
    ("FORT WILDERNESS",     "resort",  "🏨 Fort Wilderness"),
    ("D-FORT WILDERNESS",   "resort",  "🏨 Fort Wilderness"),
    ("GRAN DESTINO",        "resort",  "🏨 Gran Destino"),
    ("D-GRAN DESTINO",      "resort",  "🏨 Gran Destino"),
    ("D-Gran Destino",      "resort",  "🏨 Gran Destino"),
    ("GRAND FLORIDIAN",     "resort",  "🏨 Grand Floridian"),
    ("D-GRAND FLORIDIAN",   "resort",  "🏨 Grand Floridian"),
    ("D-GRAND FLORIDIAN",   "resort",  "🏨 Grand Floridian"),
    ("Island Tower Polynesian", "resort", "🏨 Island Tower Polynesian"),
    ("D-Island Tower",      "resort",  "🏨 Island Tower"),
    ("Kidani Village",      "resort",  "🏨 Kidani Village"),
    ("D-Kidani Village",    "resort",  "🏨 Kidani Village"),
    ("OLD KEY WEST",        "resort",  "🏨 Old Key West"),
    ("D-OLD KEY WEST",      "resort",  "🏨 Old Key West"),
    ("POLYNESIAN RESORT",   "resort",  "🏨 Polynesian Resort"),
    ("D-POLYNESIAN RESORT", "resort",  "🏨 Polynesian Resort"),
    ("POP CENTURY",         "resort",  "🏨 Pop Century"),
    ("D-POP CENTURY",       "resort",  "🏨 Pop Century"),
    ("PORT ORLEANS FrQt",   "resort",  "🏨 Port Orleans French Quarter"),
    ("D-Port Orleans FrQt", "resort",  "🏨 Port Orleans French Quarter"),
    ("Port Orleans Rvsd",   "resort",  "🏨 Port Orleans Riverside"),
    ("D-Port Orleans Rvsd", "resort",  "🏨 Port Orleans Riverside"),
    ("RIVIERA RESORT",      "resort",  "🏨 Riviera Resort"),
    ("D-RIVIERA RESORT",    "resort",  "🏨 Riviera Resort"),
    ("Saratoga Springs",    "resort",  "🏨 Saratoga Springs"),
    ("D-Saratoga Springs",  "resort",  "🏨 Saratoga Springs"),
    ("Treehouse Villas",    "resort",  "🏨 Treehouse Villas"),
    ("D-Treehouse Villas",  "resort",  "🏨 Treehouse Villas"),
    ("TYPHOON LAGOON CAST", "resort",  "🏨 Typhoon Lagoon"),
    ("D-TYPHOON LAGOON",    "resort",  "🏨 Typhoon Lagoon"),
    ("WILDERNESS LODGE",    "resort",  "🏨 Wilderness Lodge"),
    ("D-WILDERNESS LODGE",  "resort",  "🏨 Wilderness Lodge"),
    ("Winter Summerland",   "resort",  "🏨 Winter Summerland"),
    ("D-Winter Summerland", "resort",  "🏨 Winter Summerland"),
    ("YACHT AND BEACH",     "resort",  "🏨 Yacht and Beach"),
    ("D-YACHT AND BEACH",   "resort",  "🏨 Yacht and Beach"),
]

# ── Office mapping ────────────────────────────────────────────────────────────
OFFICE_MAPPING = [
    ("DRC Cast",    "office",  "🏢 DRC"),
]

# ── Other mapping ─────────────────────────────────────────────────────────────
OTHER_MAPPING = [
    ("DISNEY VENDING",       "other",  "📍 Disney Vending"),
    ("DISNEY WORLD SS",      "other",  "📍 Support Services"),
    ("D-ESPN",               "other",  "📍 ESPN"),
    ("ESPN",                 "other",  "📍 ESPN"),
    ("WIDE WORLD SPORTS",    "other",  "📍 Wide World of Sports"),
    ("D-WIDE WORLD SPORTS",  "other",  "📍 Wide World of Sports"),
    ("Celebration",          "other",  "📍 Celebration"),
    ("D-Celebration",        "other",  "📍 Celebration"),
]

# ── Build the full mapping ────────────────────────────────────────────────────
# Preprocess: lowercase all patterns for case-insensitive matching
# Order matters: more specific patterns come first

def _normalise(name):
    """Strip D- prefix checks and normalise whitespace."""
    return ' '.join(name.split()).upper()

def _build_location_mapping():
    """Build dict: location_name_upper -> (disney_park_code, display_name)."""
    mapping = {}

    # Park patterns - we'll handle these specially since we're doing substring matching
    park_patterns = [
        # (substring_check_fn, code, display_name)
    ]

    # Resort patterns
    resort_patterns = []
    for substr, code, display in PARK_MAPPING:
        if substr is None:
            continue
        resort_patterns.append((substr.upper(), code, display))

    office_patterns = []
    for substr, code, display in OFFICE_MAPPING:
        office_patterns.append((substr.upper(), code, display))

    other_patterns = []
    for substr, code, display in OTHER_MAPPING:
        other_patterns.append((substr.upper(), code, display))

    # Park detection patterns (ordered by specificity)
    # These need to be checked BEFORE the generic patterns
    park_checks = [
        # Check for specific parks first
        (lambda n: "MAGIC KINGDOM" in n, "magic-kingdom", "🏰 Magic Kingdom"),
        (lambda n: n.startswith("D-EPCOT"), "epcot", "🌍 Epcot"),
        (lambda n: "EPCOT CAST" in n, "epcot", "🌍 Epcot"),
        (lambda n: "EPCOT GUEST" in n, "epcot", "🌍 Epcot"),
        (lambda n: "EPCOT" in n and n.startswith("D-"), "epcot", "🌍 Epcot"),
        (lambda n: "HOLLYWOOD STUDIOS" in n, "hollywood-studios", "🎬 Hollywood Studios"),
        (lambda n: "ANIMAL KINGDOM" in n and "LODGE" not in n and "CAST" in n, "animal-kingdom", "🌿 Animal Kingdom"),
        (lambda n: "ANIMAL KNGDM" in n and "LODGE" not in n and "LODG" not in n, "animal-kingdom", "🌿 Animal Kingdom"),
        (lambda n: "ANIMAL KINGDOM GUEST" in n, "animal-kingdom", "🌿 Animal Kingdom"),
        (lambda n: "DISNEY SPRINGS" in n, "disney-springs", "🛍️ Disney Springs"),
    ]

    def classify(name):
        """Return (code, display) for a Disney location name, or None."""
        n = _normalise(name)

        # 1) Check parks first (most specific)
        for check_fn, code, display in park_checks:
            if check_fn(n):
                return code, display

        # 2) Check office
        for substr, code, display in office_patterns:
            if substr in n:
                return code, display

        # 3) Check resorts
        for substr, code, display in resort_patterns:
            if substr in n:
                return code, display

        # 4) Check other
        for substr, code, display in other_patterns:
            if substr in n:
                return code, display

        return None

    return classify


def get_db_path():
    """Find the assets.db path."""
    # Try common locations
    candidates = [
        os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "assets.db"),
        "/home/oplabs/projects/canteen-asset-tracker/assets.db",
    ]
    for p in candidates:
        if os.path.exists(p):
            return p
    raise FileNotFoundError("Could not find assets.db")


def main():
    parser = argparse.ArgumentParser(description="Tag Disney assets with park/resort codes")
    parser.add_argument("--apply", action="store_true", help="Actually update the database")
    args = parser.parse_args()

    classify = _build_location_mapping()

    db_path = get_db_path()
    print(f"Database: {db_path}")
    conn = sqlite3.connect(db_path)
    conn.row_factory = sqlite3.Row
    cur = conn.cursor()

    # ── Step 1: Load all Disney locations ────────────────────────────────────
    cur.execute("SELECT id, name FROM locations ORDER BY name")
    all_locations = [dict(r) for r in cur.fetchall()]

    # Build: location_id -> (disney_park_code, display_name)
    loc_park_map = {}       # location_id -> (code, display_name)
    loc_display_map = {}    # location_id -> display_name (for appending)
    unmapped_locations = []

    for loc in all_locations:
        name = loc["name"]
        result = classify(name)
        if result:
            loc_park_map[loc["id"]] = result
        else:
            # Check if this is a Disney location (starts with D-, DISNEY, DRC, Disney Springs)
            n_upper = _normalise(name)
            if any(name.startswith(p) for p in ["D-", "DISNEY", "DRC", "Disney Springs"]):
                n = _normalise(name)
                if n.startswith("D-ANIMAL KINGDOM") and "LODGE" not in n:
                    loc_park_map[loc["id"]] = ("animal-kingdom", "🌿 Animal Kingdom")
                elif n.startswith("D-ANIMAL KNGDM") and "LODGE" not in n:
                    loc_park_map[loc["id"]] = ("animal-kingdom", "🌿 Animal Kingdom")
                else:
                    unmapped_locations.append(loc)
            # Non-Disney locations are ignored

    # ── Step 1b: Print unmapped Disney locations ─────────────────────────────
    if unmapped_locations:
        print(f"\n⚠️  {len(unmapped_locations)} Disney locations could not be mapped:")
        for loc in unmapped_locations:
            print(f"    ID {loc['id']}: {loc['name']}")

    # ── Step 2: Update assets ────────────────────────────────────────────────
    cur.execute("SELECT id, name, location_id FROM assets WHERE is_disney=1")
    disney_assets = [dict(r) for r in cur.fetchall()]

    park_counts = {}
    name_updates = []
    name_skipped = []

    for asset in disney_assets:
        loc_id = asset["location_id"]
        if loc_id not in loc_park_map:
            continue
        code, display = loc_park_map[loc_id]
        park_counts[display] = park_counts.get(display, 0) + 1

        # Check if the display name is already appended
        current_name = asset["name"]
        suffix = f" {display}"
        if suffix not in current_name:
            new_name = current_name + suffix
            name_updates.append((code, new_name, asset["id"]))
        else:
            name_skipped.append((asset["id"], current_name))
            # Still update the disney_park code even if name already has suffix
            name_updates.append((code, current_name, asset["id"]))

    # ── Step 3: Identify locations that need updating ────────────────────────
    # Check if locations has the column
    cur.execute("PRAGMA table_info(locations)")
    loc_cols = [r["name"] for r in cur.fetchall()]
    needs_add_column = "disney_park" not in loc_cols

    # Build set of location IDs that are Disney
    disney_loc_ids = set(loc_park_map.keys())

    print(f"\n{'='*60}")
    print(f"MODE: {'APPLY' if args.apply else 'DRY-RUN'} (pass --apply to execute)")
    print(f"{'='*60}")

    print(f"\n📊 Summary: {len(disney_assets)} Disney assets, {len(loc_park_map)} mapped locations")

    print(f"\n📋 Assets per park/resort:")
    for display, count in sorted(park_counts.items(), key=lambda x: -x[1]):
        print(f"    {display}: {count} assets")

    print(f"\n📝 Name updates: {len(name_updates)}")
    print(f"⏭️  Already tagged (skipped): {len(name_skipped)}")

    # Show a sample
    print(f"\n🔍 Sample updates (first 5):")
    for i, (code, new_name, aid) in enumerate(name_updates[:5]):
        old = next((a["name"] for a in disney_assets if a["id"] == aid), "")
        print(f"    Asset {aid}:")
        print(f"      Before: {old}")
        print(f"      After:  {new_name}")
        print(f"      Park:   {code}")

    # ── Execute updates ──────────────────────────────────────────────────────
    if args.apply:
        print(f"\n{'='*60}")
        print("APPLYING CHANGES...")
        print(f"{'='*60}")

        # Update assets
        updated_assets = 0
        for code, new_name, aid in name_updates:
            cur.execute(
                "UPDATE assets SET disney_park = ?, name = ? WHERE id = ?",
                (code, new_name, aid),
            )
            updated_assets += 1

        # Add column to locations if needed
        if needs_add_column:
            print(f"\n  Adding disney_park column to locations table...")
            cur.execute("ALTER TABLE locations ADD COLUMN disney_park TEXT DEFAULT NULL")

        # Update locations
        updated_locations = 0
        for loc_id, (code, display) in loc_park_map.items():
            cur.execute(
                "UPDATE locations SET disney_park = ? WHERE id = ?",
                (code, loc_id),
            )
            updated_locations += 1

        conn.commit()
        print(f"\n✅ Done! Updated {updated_assets} assets and {updated_locations} locations.")
    else:
        print(f"\n💡 Run with --apply to execute these changes.")
        if needs_add_column:
            print("  (Note: disney_park column will be added to locations table)")

    conn.close()


if __name__ == "__main__":
    main()
