"""SQLite database schema and CRUD operations for Dad's Video Catalog."""

import re
import sqlite3
import sys

import numpy as np
from rich.console import Console
from rich.table import Table

from .config import DB_PATH


def get_db(db_path=None):
    """Get a database connection with row factory."""
    conn = sqlite3.connect(db_path or DB_PATH)
    conn.row_factory = sqlite3.Row
    conn.execute("PRAGMA journal_mode=WAL")
    conn.execute("PRAGMA foreign_keys=ON")
    return conn


SCHEMA = """
CREATE TABLE IF NOT EXISTS videos (
    id INTEGER PRIMARY KEY,
    number INTEGER NOT NULL UNIQUE,
    filename TEXT NOT NULL UNIQUE,
    title TEXT,
    duration_seconds REAL,
    year TEXT,
    category TEXT,
    notes TEXT,
    gps_lat REAL,
    gps_lon REAL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE IF NOT EXISTS frames (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    video_id INTEGER NOT NULL REFERENCES videos(id),
    path TEXT NOT NULL,
    timestamp_seconds REAL NOT NULL,
    width INTEGER,
    height INTEGER,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_frames_video ON frames(video_id);

CREATE TABLE IF NOT EXISTS people (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL UNIQUE,
    description TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE IF NOT EXISTS faces (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    frame_id INTEGER NOT NULL REFERENCES frames(id),
    video_id INTEGER NOT NULL REFERENCES videos(id),
    person_id INTEGER REFERENCES people(id),
    path TEXT NOT NULL,
    x INTEGER NOT NULL,
    y INTEGER NOT NULL,
    width INTEGER NOT NULL,
    height INTEGER NOT NULL,
    confidence REAL,
    encoding BLOB,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_faces_person ON faces(person_id);
CREATE INDEX IF NOT EXISTS idx_faces_video ON faces(video_id);
CREATE INDEX IF NOT EXISTS idx_faces_untagged ON faces(person_id) WHERE person_id IS NULL;

CREATE TABLE IF NOT EXISTS places (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL UNIQUE,
    region TEXT,
    description TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE IF NOT EXISTS video_places (
    video_id INTEGER NOT NULL REFERENCES videos(id),
    place_id INTEGER NOT NULL REFERENCES places(id),
    PRIMARY KEY (video_id, place_id)
);

CREATE TABLE IF NOT EXISTS tags (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    name TEXT NOT NULL UNIQUE,
    category TEXT,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

CREATE TABLE IF NOT EXISTS video_tags (
    video_id INTEGER NOT NULL REFERENCES videos(id),
    tag_id INTEGER NOT NULL REFERENCES tags(id),
    PRIMARY KEY (video_id, tag_id)
);

CREATE TABLE IF NOT EXISTS video_people (
    video_id INTEGER NOT NULL REFERENCES videos(id),
    person_id INTEGER NOT NULL REFERENCES people(id),
    PRIMARY KEY (video_id, person_id)
);
"""


def migrate_db(conn):
    """Apply schema migrations for existing databases."""
    cursor = conn.execute("PRAGMA table_info(faces)")
    face_cols = {row[1] for row in cursor.fetchall()}
    if "encoding" not in face_cols:
        conn.execute("ALTER TABLE faces ADD COLUMN encoding BLOB")
        print("  Migration: added encoding column to faces")

    cursor = conn.execute("PRAGMA table_info(videos)")
    video_cols = {row[1] for row in cursor.fetchall()}
    if "gps_lat" not in video_cols:
        conn.execute("ALTER TABLE videos ADD COLUMN gps_lat REAL")
        conn.execute("ALTER TABLE videos ADD COLUMN gps_lon REAL")
        print("  Migration: added gps_lat/gps_lon columns to videos")

    conn.commit()


def init_db():
    """Create database schema."""
    conn = get_db()
    conn.executescript(SCHEMA)
    migrate_db(conn)
    conn.commit()
    print(f"Database initialized at {DB_PATH}")
    conn.close()


def seed_people(conn):
    """Pre-seed known people."""
    people = [
        (
            "Dad",
            "Dark-haired man, later with mustache. Often in sunglasses"
            " and leather jacket. The filmmaker behind most footage.",
        ),
        ("Mom", "Long-haired woman, auburn/reddish. Stylish through the decades."),
        ("Beth", "Born ~1963. Eldest child. Age 2 at Memorial Day Picnic, 1965."),
        ("Rusty", "Child featured in Florida Keys footage."),
        ("Jennifer", "Born June 1969. Dark hair. 4th birthday party filmed in Wilmette, IL."),
        ("Kelly", "Featured March 1978."),
        ("Grandma Pollock", "Older family member, at 1966 family picnic."),
        (
            "Sandy Straus",
            "Young woman with reddish-blonde hair. Two reels of footage dedicated to her.",
        ),
        (
            "Grandfather Figure",
            "Distinguished gray-haired man with mustache."
            " Seen holding baby and playing on couch.",
        ),
    ]
    for name, desc in people:
        conn.execute(
            "INSERT OR IGNORE INTO people (name, description) VALUES (?, ?)",
            (name, desc),
        )
    conn.commit()
    print(f"  Seeded {len(people)} people")


def seed_places(conn):
    """Pre-seed known places."""
    places = [
        ("Wilmette, Illinois", "USA", "Family home - north shore Chicago suburb"),
        ("Sacre Coeur, Paris", "France", "Observation deck atop Montmartre"),
        ("Versailles", "France", "Palace and gardens"),
        ("Louvre", "France", "Museum in Paris"),
        ("Paris Monuments", "France", "Pantheon area, Notre-Dame area"),
        ("Sovereign Airways", "France", "Flight to France - family boarding aircraft on tarmac"),
        ("Havasu Creek", "Grand Canyon", "Turquoise waters among canyon boulders"),
        ("Colorado River", "Grand Canyon", "Multi-day rafting trip - Lees Ferry to Lava Falls"),
        ("Lees Ferry", "Grand Canyon", "Launch point for river trips"),
        ("Lava Falls", "Grand Canyon", "Major rapid on Colorado River"),
        ("Independence Pass", "Colorado", "Mountain overlook, 1971"),
        ("Vaughn Lake", "Colorado", "Mountain viewpoint, 1971"),
        ("Arches National Monument", "Colorado", "Utah/Colorado border area, 1971"),
        ("Masada", "Israel", "Ancient fortress with IDF soldier visible"),
        ("Dead Sea", "Israel", "Salt lake, 1971"),
        ("Omo River", "Ethiopia", "River expedition through lush green mountains"),
        ("Walt Disney World", "Florida", "Liberty Square, carousel, Apollo 7 exhibit"),
        ("Cypress Gardens", "Florida", "South Sea Waterfall, water ski shows"),
        ("Lion Country Safari", "Florida", "Drive-through wildlife park"),
        ("Cape Kennedy", "Florida", "Apollo/Saturn V launch history display"),
        ("Miami Beach", "Florida", "Beach scenes"),
        ("Key West", "Florida", "Road trip destination"),
        ("Seminole Village", "Florida", "Miccosukee/Seminole traditional village"),
        ("Islamorada", "Florida", "Florida Keys"),
        (
            "Killarney Provincial Park",
            "Canada",
            "Red log cabin on lake, annual canoe trips 1962-1968",
        ),
        ("Expo 67, Montreal", "Canada", "World exposition, 1967"),
        ("Mexico (1976)", "Mexico", "Yacht trips, fishing, village visits, porpoise watching"),
        ("Baja (1978)", "Mexico", "Beach and coast, March 1978"),
        ("Playboy Club-Hotel", "Wisconsin", "Lake Geneva, WI - ski trips and family visits"),
        ("Kroc Ranch", "Other", "Ray Kroc's ranch - upscale lodge interior"),
        ("Three Rivers Stadium", "Pennsylvania", "Pittsburgh Pirates baseball games"),
    ]
    for name, region, desc in places:
        conn.execute(
            "INSERT OR IGNORE INTO places (name, region, description) VALUES (?, ?, ?)",
            (name, region, desc),
        )
    conn.commit()
    print(f"  Seeded {len(places)} places")


def seed_tags(conn):
    """Pre-seed known tags."""
    tags = [
        ("Family", "family"),
        ("Travel", "travel"),
        ("France", "travel"),
        ("Grand Canyon", "travel"),
        ("Mexico", "travel"),
        ("Florida", "travel"),
        ("Israel", "travel"),
        ("Colorado", "travel"),
        ("Canada", "travel"),
        ("Wisconsin", "travel"),
        ("Ethiopia", "travel"),
        ("Ranch", "travel"),
        ("Dance", "event"),
        ("Birthday", "event"),
        ("Birth", "event"),
        ("Baseball", "event"),
        ("Activity", "event"),
        ("Event", "event"),
        ("Novelty Film", "novelty"),
    ]
    for name, category in tags:
        conn.execute(
            "INSERT OR IGNORE INTO tags (name, category) VALUES (?, ?)",
            (name, category),
        )
    conn.commit()
    print(f"  Seeded {len(tags)} tags")


def parse_duration(dur_str):
    """Parse duration string like '3m 18s' or '13m 27s' to seconds."""
    m = re.match(r"(\d+)m\s*(\d+)s", dur_str)
    if m:
        return int(m.group(1)) * 60 + int(m.group(2))
    return None


# Video data extracted from catalog.html
# (number, filename, title, duration_str, year, tags_list)
VIDEO_DATA = [
    (1, "001._Picnic_02.mp4", "Picnic 02", "3m 18s", None, ["Family"]),
    (2, "002._Untitled.mp4", "Paris - Monumental Buildings", "3m 18s", None, ["France"]),
    (3, "003._78_6.mp4", "Grand Canyon (June 1978)", "3m 19s", "1978", ["Grand Canyon"]),
    (
        4,
        "004._78_6_large_Cavern.mp4",
        "Large Cavern (June 1978)",
        "3m 17s",
        "1978",
        ["Grand Canyon"],
    ),
    (5, "005._76_Mex__77_Me.mp4", "Mexico 1976 / 1977", "3m 17s", "1976", ["Mexico"]),
    (6, "006._Untitled.mp4", "Paris - Aerial City View", "3m 19s", None, ["France"]),
    (
        7,
        "007._78_6_Fight_to_Lees.mp4",
        "Flight to Lees Ferry (June 1978)",
        "3m 17s",
        "1978",
        ["Grand Canyon"],
    ),
    (
        8,
        "008._78_6_Crystal_Day_Bay.mp4",
        "Crystal Day Bay (June 1978)",
        "3m 18s",
        "1978",
        ["Grand Canyon"],
    ),
    (9, "009._Sacre_Cour.mp4", "Sacre Coeur, Paris", "3m 18s", None, ["France"]),
    (10, "010._78_6_Havasu.mp4", "Havasu Creek (June 1978)", "3m 18s", "1978", ["Grand Canyon"]),
    (
        11,
        "011._76_Oct_Mexico_Fishing.mp4",
        "Mexico Fishing (Oct 1976)",
        "3m 18s",
        "1976",
        ["Mexico"],
    ),
    (12, "012._Versailles.mp4", "Versailles", "3m 18s", None, ["France"]),
    (13, "013._Untitled.mp4", "France - Cathedral Exterior", "2m 50s", None, ["France"]),
    (14, "014._76_Oct_Mexico_03.mp4", "Mexico 03 (Oct 1976)", "3m 16s", "1976", ["Mexico"]),
    (
        15,
        "015._Hall_of_Fame_FLA_1977_12_Baja_1978_3.mp4",
        "Hall of Fame FLA (Dec 1977) / Baja (Mar 1978)",
        "3m 19s",
        "1977",
        ["Florida", "Mexico"],
    ),
    (16, "016._1978_Kelly_March.mp4", "Kelly (March 1978)", "3m 7s", "1978", ["Family"]),
    (17, "017._78_6_Baha_Sands.mp4", "Baja Sands (June 1978)", "3m 17s", "1978", ["Mexico"]),
    (
        18,
        "018._76_Oct_Mexico_Porpoise_Jump.mp4",
        "Mexico Porpoise Jump (Oct 1976)",
        "3m 18s",
        "1976",
        ["Mexico"],
    ),
    (
        19,
        "019._76_Oct_Mexico_Village.mp4",
        "Mexico Village (Oct 1976)",
        "3m 17s",
        "1976",
        ["Mexico"],
    ),
    (20, "020._Untitled.mp4", "Dance / Ballet Class", "3m 19s", None, ["Dance"]),
    (21, "021._1978_3_Baja.mp4", "Baja (March 1978)", "3m 19s", "1978", ["Mexico"]),
    (22, "022._1978_Lees_Ferry.mp4", "Lees Ferry (1978)", "3m 18s", "1978", ["Grand Canyon"]),
    (23, "023._78_3_Baja.mp4", "Baja (March 1978)", "3m 19s", "1978", ["Mexico"]),
    (24, "024._1977_NMC.mp4", "NMC (1977)", "3m 19s", "1977", ["Event"]),
    (25, "025._Versailles_Picnic.mp4", "Versailles Picnic", "3m 17s", None, ["France"]),
    (26, "026._1978_6_Lava.mp4", "Lava Falls (June 1978)", "3m 18s", "1978", ["Grand Canyon"]),
    (
        27,
        "027._78_6_Water_Fast.mp4",
        "Water Fast / Waterfall (June 1978)",
        "3m 17s",
        "1978",
        ["Grand Canyon"],
    ),
    (28, "028._Untitled.mp4", "Dance Recital", "3m 6s", None, ["Dance"]),
    (29, "029._Louvre_02.mp4", "Louvre 02", "3m 19s", None, ["France"]),
    (
        30,
        "030._1972_Cypress_Gardens.mp4",
        "Cypress Gardens (1972)",
        "3m 17s",
        "1972",
        ["Florida"],
    ),
    (
        31,
        "031._1972_Cypress_Gardens_01.mp4",
        "Cypress Gardens 01 (1972)",
        "3m 16s",
        "1972",
        ["Florida"],
    ),
    (
        32,
        "032._78_6_Easter_Day_02.mp4",
        "Easter Day 02 (June 1978)",
        "3m 18s",
        "1978",
        ["Grand Canyon"],
    ),
    (33, "033._France_01.mp4", "France 01 / Sovereign Airways", "3m 18s", None, ["France"]),
    (34, "034._Cypress_Gardens.mp4", "Cypress Gardens", "3m 19s", None, ["Florida"]),
    (35, "035._Disney_World.mp4", "Disney World - Liberty Square", "3m 19s", None, ["Florida"]),
    (36, "036._Lion_Country_Fair.mp4", "Lion Country Fair", "3m 18s", None, ["Florida"]),
    (
        37,
        "037._Rusty_Islamarada.mp4",
        "Rusty - Islamorada / Seminole Village",
        "3m 17s",
        None,
        ["Family", "Florida"],
    ),
    (38, "038._Lion_Country_Safari.mp4", "Lion Country Safari", "3m 18s", None, ["Florida"]),
    (
        39,
        "039._Untitled.mp4",
        "Jennifer's 4th Birthday, Wilmette, IL (~1973)",
        "3m 19s",
        "1973",
        ["Family", "Birthday"],
    ),
    (40, "040._1971_Israel_Masada.mp4", "Israel - Masada (1971)", "3m 18s", "1971", ["Israel"]),
    (41, "041._Untitled.mp4", "Birthday Party", "3m 18s", None, ["Family", "Birthday"]),
    (
        42,
        "042._1972_Dec_Cape_Kennedy.mp4",
        "Cape Kennedy (Dec 1972)",
        "3m 19s",
        "1972",
        ["Florida"],
    ),
    (43, "043._1971_Aug_Israel.mp4", "Israel (Aug 1971)", "3m 18s", "1971", ["Israel"]),
    (
        44,
        "044._Alligator_Wrestling.mp4",
        "Alligator Wrestling / Seminole Village",
        "3m 19s",
        None,
        ["Florida"],
    ),
    (45, "045._Horseback_Riding_02.mp4", "Horseback Riding 02", "3m 17s", None, ["Activity"]),
    (46, "046._1974_Oct_Ranch_03.mp4", "Ranch (Oct 1974)", "2m 56s", "1974", ["Ranch"]),
    (47, "047._No_03.mp4", "No. 03", "3m 19s", None, []),
    (48, "048._No_02.mp4", "No. 02", "3m 18s", None, []),
    (49, "049._No_01.mp4", "No. 01", "3m 18s", None, []),
    (50, "050._1971_Dead_Sea.mp4", "Dead Sea (1971)", "3m 20s", "1971", ["Israel"]),
    (51, "051._Lion_Country_Safari.mp4", "Lion Country Safari", "3m 19s", None, ["Florida"]),
    (52, "052._Disney_World.mp4", "Disney World", "3m 19s", None, ["Florida"]),
    (53, "053._Untitled.mp4", "Pittsburgh Pirates Baseball", "3m 19s", None, ["Baseball"]),
    (54, "054._Miami_Beach.mp4", "Miami Beach", "3m 19s", None, ["Florida"]),
    (
        55,
        "055._Cypress_Gardens_01.mp4",
        "Cypress Gardens 01 - South Sea Waterfall",
        "3m 17s",
        None,
        ["Florida"],
    ),
    (56, "056._On_Board_Jet_01.mp4", "On Board Jet 01", "3m 16s", None, ["Travel"]),
    (
        57,
        "057._Disney_World.mp4",
        "Disney World - Apollo 7 Exhibit",
        "3m 19s",
        None,
        ["Florida"],
    ),
    (58, "058._Disney_World.mp4", "Disney World - Carousel & Park", "3m 21s", None, ["Florida"]),
    (
        59,
        "059._Untitled.mp4",
        "Baseball Stadium Event / Ronald McDonald",
        "3m 18s",
        None,
        ["Baseball"],
    ),
    (60, "060._Lost_Dollar.mp4", "Lost Dollar", "3m 15s", None, []),
    (61, "061._Camper.mp4", "Camper", "3m 19s", None, []),
    (62, "062._Lost_Dollar.mp4", "Lost Dollar", "3m 20s", None, []),
    (63, "063._Kroc_Ranch.mp4", "Kroc Ranch", "3m 17s", None, ["Ranch"]),
    (
        64,
        "064._Cape_Kennedy.mp4",
        "Cape Kennedy - Apollo/Saturn V Display",
        "3m 19s",
        None,
        ["Florida"],
    ),
    (65, "065._Road_to_Key_West.mp4", "Road to Key West", "3m 19s", None, ["Florida"]),
    (66, "066._Cypress_Gardens_02.mp4", "Cypress Gardens 02", "3m 18s", None, ["Florida"]),
    (
        67,
        "067._1968_Killarney_Bad_Blank.mp4",
        "Killarney (1968) - Damaged",
        "1m 12s",
        "1968",
        ["Canada"],
    ),
    (68, "068._Little_Rascals.mp4", "Little Rascals", "3m 33s", None, ["Novelty Film"]),
    (
        69,
        "069._1971_Colorado_Vaughn_Lake.mp4",
        "Colorado - Vaughn Lake (1971)",
        "3m 40s",
        "1971",
        ["Colorado"],
    ),
    (
        70,
        "070._1972_Feb_7_and_8_Playboy_Ski.mp4",
        "Playboy Ski, Lake Geneva (Feb 1972)",
        "2m 3s",
        "1972",
        ["Wisconsin"],
    ),
    (71, "071._Sandy_Staus_02.mp4", "Sandy Straus 02", "4m 7s", None, ["Family"]),
    (
        72,
        "072._1969_June_Jennifer_at_Birth.mp4",
        "Jennifer at Birth (June 1969)",
        "3m 30s",
        "1969",
        ["Family", "Birth"],
    ),
    (73, "073._Mr_Magoo.mp4", "Mr. Magoo", "1m 50s", None, ["Novelty Film"]),
    (74, "074._Untitled.mp4", "Dance Recital & Children", "3m 33s", None, ["Dance"]),
    (
        75,
        "075._1965_Killarney_Great.mp4",
        "Killarney - Great (1965)",
        "4m 7s",
        "1965",
        ["Canada"],
    ),
    (
        76,
        "076._1966_Picnic_Grandma_Pollock.mp4",
        "Picnic w/ Grandma Pollock (1966) / Playboy Club",
        "3m 21s",
        "1966",
        ["Family", "Wisconsin"],
    ),
    (77, "077._Carnival_Films.mp4", "Carnival Films", "3m 4s", None, ["Novelty Film"]),
    (78, "078._Kitty_Kat.mp4", "Kitty Kat", "2m 11s", None, ["Novelty Film"]),
    (
        79,
        "079._1971_Colorado_Independence_Pass.mp4",
        "Colorado - Independence Pass (1971)",
        "3m 57s",
        "1971",
        ["Colorado", "Family"],
    ),
    (
        80,
        "080._1971_Colorado_Arches_National_Mon.mp4",
        "Colorado - Arches National Monument (1971)",
        "3m 12s",
        "1971",
        ["Colorado"],
    ),
    (81, "081._1964_to_65_Canada.mp4", "Canada (1964-65)", "3m 25s", "1964", ["Canada"]),
    (82, "082._1962_Killarney.mp4", "Killarney (1962)", "3m 24s", "1962", ["Canada"]),
    (83, "083._Sandy_Straus_01.mp4", "Sandy Straus 01", "3m 24s", None, ["Family"]),
    (
        84,
        "084._Olliue_Look_at_These_Great_Aesop_Fables.mp4",
        "Ollie / Aesop Fables",
        "2m 59s",
        None,
        ["Novelty Film"],
    ),
    (
        85,
        "085._1967_Killarney_Canoes_to_Expo.mp4",
        "Killarney Canoes to Expo 67 (1967)",
        "3m 25s",
        "1967",
        ["Canada"],
    ),
    (86, "086._Untitled.mp4", "Lake Cabin (Killarney)", "1m 28s", None, ["Canada"]),
    (87, "087._Untitled.mp4", "Grandfather with Baby & Young Boy", "4m 9s", None, ["Family"]),
    (88, "088._Untitled.mp4", "Baja Coastline", "2m 28s", None, ["Mexico"]),
    (
        89,
        "089._Untitled.mp4",
        "Early Family - Young Mom & Toddler (~late 1950s)",
        "2m 1s",
        "1958",
        ["Family"],
    ),
    (
        90,
        "090._1978_6_Flight_to_Lees_Ferry.mp4",
        "Flight to Lees Ferry (June 1978)",
        "0m 6s",
        "1978",
        ["Grand Canyon"],
    ),
    (91, "091._Untitled.mp4", "Amusement Park Boat Ride", "1m 27s", None, ["Activity"]),
    (92, "092._1940.mp4", "Beach Scenes (1940)", "2m 7s", "1940", ["Family"]),
    (93, "093._Untitled.mp4", "Toddler in Backyard (early 1960s)", "2m 15s", "1960", ["Family"]),
    (
        94,
        "094._Untitled.mp4",
        "Grand Canyon River Rafting (June 1978)",
        "13m 27s",
        "1978",
        ["Grand Canyon"],
    ),
    (95, "095._Untitled.mp4", "Carnival Films Cartoons", "11m 42s", None, ["Novelty Film"]),
    (96, "096._Untitled.mp4", "Florida Boating / Fishing", "15m 35s", None, ["Florida"]),
    (97, "097._Untitled.mp4", "Omo River Expedition, Ethiopia", "8m 37s", None, ["Ethiopia"]),
    (98, "098._Untitled.mp4", "Vintage Cartoon", "17m 1s", None, ["Novelty Film"]),
    (
        99,
        "099._Honeymoon_thru_Beth_Age_2_Memorial_Day_Picnic_1965.mp4",
        "Honeymoon thru Beth Age 2 - Memorial Day 1965",
        "36m 22s",
        "1963",
        ["Family"],
    ),
    (
        100,
        "100._Untitled.mp4",
        "Omo River Expedition, Ethiopia (continued)",
        "24m 44s",
        None,
        ["Ethiopia"],
    ),
    (
        101,
        "101.__Untitled.mp4",
        "Pittsburgh Pirates Baseball & More",
        "27m 31s",
        None,
        ["Baseball"],
    ),
]

# Known person-video associations from catalog
PERSON_VIDEOS = {
    "Dad": [69, 94, 99, 70],
    "Mom": [79, 5, 39, 89],
    "Beth": [99],
    "Rusty": [37],
    "Jennifer": [72, 79, 39],
    "Kelly": [16],
    "Grandma Pollock": [76],
    "Sandy Straus": [71, 83],
    "Grandfather Figure": [87],
}

# Known place-video associations
PLACE_VIDEOS = {
    "Wilmette, Illinois": [39],
    "Sacre Coeur, Paris": [2, 6, 9, 12, 13, 25, 29, 33],
    "Versailles": [12, 25],
    "Louvre": [29],
    "Paris Monuments": [2, 6, 12, 13, 25, 29],
    "Sovereign Airways": [33],
    "Havasu Creek": [10],
    "Colorado River": [3, 4, 7, 8, 22, 26, 27, 32, 90, 94],
    "Lees Ferry": [7, 22, 90],
    "Lava Falls": [26],
    "Independence Pass": [79],
    "Vaughn Lake": [69],
    "Arches National Monument": [80],
    "Masada": [40, 43, 50],
    "Dead Sea": [50],
    "Omo River": [97, 100],
    "Walt Disney World": [35, 52, 57, 58],
    "Cypress Gardens": [30, 31, 34, 55, 66],
    "Lion Country Safari": [36, 38, 51],
    "Cape Kennedy": [42, 64],
    "Miami Beach": [54],
    "Key West": [65],
    "Seminole Village": [37, 44],
    "Islamorada": [37],
    "Killarney Provincial Park": [67, 75, 81, 82, 85, 86],
    "Expo 67, Montreal": [85],
    "Mexico (1976)": [5, 11, 14, 18, 19],
    "Baja (1978)": [17, 21, 23, 88],
    "Playboy Club-Hotel": [70, 76],
    "Kroc Ranch": [60, 62, 63],
    "Three Rivers Stadium": [53, 59, 101],
}


def import_videos(conn):
    """Import all video metadata."""
    count = 0
    for number, filename, title, dur_str, year, _ in VIDEO_DATA:
        duration = parse_duration(dur_str)
        # Determine category
        category = None
        if any(t in ["Novelty Film"] for t in VIDEO_DATA[number - 1][5]):
            category = "novelty"
        elif any(t in ["Family", "Birthday", "Birth"] for t in VIDEO_DATA[number - 1][5]):
            category = "family"
        elif any(
            t
            in [
                "France",
                "Grand Canyon",
                "Mexico",
                "Florida",
                "Israel",
                "Colorado",
                "Canada",
                "Wisconsin",
                "Ethiopia",
                "Travel",
                "Ranch",
            ]
            for t in VIDEO_DATA[number - 1][5]
        ):
            category = "travel"
        elif any(
            t in ["Dance", "Baseball", "Activity", "Event"] for t in VIDEO_DATA[number - 1][5]
        ):
            category = "event"

        conn.execute(
            """INSERT OR IGNORE INTO videos
               (number, filename, title, duration_seconds, year, category)
               VALUES (?, ?, ?, ?, ?, ?)""",
            (number, filename, title, duration, year, category),
        )
        count += 1
    conn.commit()
    print(f"  Imported {count} videos")


def import_tags(conn):
    """Associate videos with tags."""
    count = 0
    for number, _, _, _, _, tag_names in VIDEO_DATA:
        video = conn.execute("SELECT id FROM videos WHERE number = ?", (number,)).fetchone()
        if not video:
            continue
        for tag_name in tag_names:
            tag = conn.execute("SELECT id FROM tags WHERE name = ?", (tag_name,)).fetchone()
            if tag:
                conn.execute(
                    "INSERT OR IGNORE INTO video_tags (video_id, tag_id) VALUES (?, ?)",
                    (video["id"], tag["id"]),
                )
                count += 1
    conn.commit()
    print(f"  Imported {count} video-tag associations")


def import_people_videos(conn):
    """Associate people with videos."""
    count = 0
    for person_name, video_numbers in PERSON_VIDEOS.items():
        person = conn.execute("SELECT id FROM people WHERE name = ?", (person_name,)).fetchone()
        if not person:
            continue
        for vnum in video_numbers:
            video = conn.execute("SELECT id FROM videos WHERE number = ?", (vnum,)).fetchone()
            if video:
                conn.execute(
                    "INSERT OR IGNORE INTO video_people (video_id, person_id) VALUES (?, ?)",
                    (video["id"], person["id"]),
                )
                count += 1
    conn.commit()
    print(f"  Imported {count} person-video associations")


def import_place_videos(conn):
    """Associate places with videos."""
    count = 0
    for place_name, video_numbers in PLACE_VIDEOS.items():
        place = conn.execute("SELECT id FROM places WHERE name = ?", (place_name,)).fetchone()
        if not place:
            continue
        for vnum in video_numbers:
            video = conn.execute("SELECT id FROM videos WHERE number = ?", (vnum,)).fetchone()
            if video:
                conn.execute(
                    "INSERT OR IGNORE INTO video_places (video_id, place_id) VALUES (?, ?)",
                    (video["id"], place["id"]),
                )
                count += 1
    conn.commit()
    print(f"  Imported {count} place-video associations")


def import_all():
    """Import all existing data into the database."""
    conn = get_db()
    print("Importing data...")
    import_videos(conn)
    seed_people(conn)
    seed_places(conn)
    seed_tags(conn)
    import_tags(conn)
    import_people_videos(conn)
    import_place_videos(conn)
    conn.close()
    print("Import complete.")


def get_person_encodings(conn, person_id):
    """Fetch all face encodings for a tagged person."""
    rows = conn.execute(
        "SELECT id, encoding FROM faces WHERE person_id = ? AND encoding IS NOT NULL",
        (person_id,),
    ).fetchall()
    return [(row["id"], np.frombuffer(row["encoding"], dtype=np.float64)) for row in rows]


def get_untagged_encodings(conn):
    """Fetch untagged faces that have encodings."""
    rows = conn.execute(
        "SELECT id, encoding FROM faces WHERE person_id IS NULL AND encoding IS NOT NULL"
    ).fetchall()
    return [(row["id"], np.frombuffer(row["encoding"], dtype=np.float64)) for row in rows]


def print_stats():
    """Print database statistics using rich tables."""
    conn = get_db()
    console = Console()

    # Summary table
    summary = Table(title="Dad's Video Catalog - Database Stats")
    summary.add_column("Metric", style="bold")
    summary.add_column("Count", justify="right", style="cyan")

    video_count = conn.execute("SELECT COUNT(*) FROM videos").fetchone()[0]
    frame_count = conn.execute("SELECT COUNT(*) FROM frames").fetchone()[0]
    face_count = conn.execute("SELECT COUNT(*) FROM faces").fetchone()[0]
    tagged_faces = conn.execute(
        "SELECT COUNT(*) FROM faces WHERE person_id IS NOT NULL"
    ).fetchone()[0]
    untagged_faces = conn.execute(
        "SELECT COUNT(*) FROM faces WHERE person_id IS NULL"
    ).fetchone()[0]
    people_count = conn.execute("SELECT COUNT(*) FROM people").fetchone()[0]
    place_count = conn.execute("SELECT COUNT(*) FROM places").fetchone()[0]
    tag_count = conn.execute("SELECT COUNT(*) FROM tags").fetchone()[0]

    total_duration = conn.execute("SELECT SUM(duration_seconds) FROM videos").fetchone()[0] or 0
    hours = int(total_duration // 3600)
    minutes = int((total_duration % 3600) // 60)

    summary.add_row("Videos", str(video_count))
    summary.add_row("Total Duration", f"{hours}h {minutes}m")
    summary.add_row("Frames Extracted", str(frame_count))
    summary.add_row("Faces Detected", str(face_count))
    summary.add_row("Faces Tagged", str(tagged_faces))
    summary.add_row("Faces Untagged", str(untagged_faces))
    summary.add_row("People", str(people_count))
    summary.add_row("Places", str(place_count))
    summary.add_row("Tags", str(tag_count))
    console.print(summary)

    # People table
    people = conn.execute("""
        SELECT p.name, p.description,
               COUNT(DISTINCT vp.video_id) as video_count,
               COUNT(DISTINCT f.id) as face_count
        FROM people p
        LEFT JOIN video_people vp ON p.id = vp.person_id
        LEFT JOIN faces f ON p.id = f.person_id
        GROUP BY p.id
        ORDER BY video_count DESC
    """).fetchall()

    if people:
        ptable = Table(title="People")
        ptable.add_column("Name", style="bold")
        ptable.add_column("Videos", justify="right")
        ptable.add_column("Face Crops", justify="right")
        ptable.add_column("Description", max_width=50)
        for p in people:
            ptable.add_row(
                p["name"],
                str(p["video_count"]),
                str(p["face_count"]),
                (p["description"] or "")[:50],
            )
        console.print(ptable)

    # Videos by year
    years = conn.execute("""
        SELECT COALESCE(year, 'Undated') as yr, COUNT(*) as cnt,
               SUM(duration_seconds) as total_dur
        FROM videos
        GROUP BY year
        ORDER BY year
    """).fetchall()

    if years:
        ytable = Table(title="Videos by Year")
        ytable.add_column("Year", style="bold")
        ytable.add_column("Count", justify="right")
        ytable.add_column("Duration", justify="right")
        for y in years:
            dur = y["total_dur"] or 0
            ytable.add_row(str(y["yr"]), str(y["cnt"]), f"{int(dur // 60)}m {int(dur % 60)}s")
        console.print(ytable)

    conn.close()


def main():
    """Run database commands from the command line."""
    if len(sys.argv) < 2:
        print("Usage: python3 -m videocatalog.db <command>")
        print("Commands: init, import, stats")
        sys.exit(1)

    cmd = sys.argv[1]
    if cmd == "init":
        init_db()
        import_all()
    elif cmd == "import":
        import_all()
    elif cmd == "stats":
        print_stats()
    else:
        print(f"Unknown command: {cmd}")
        sys.exit(1)


if __name__ == "__main__":
    main()
