"""
Platform Gateway — Database initialization and access.
"""

import sqlite3

import bcrypt

from config import (
    DB_PATH, TRIPS_URL, FITNESS_URL, INVENTORY_URL,
    MINIFLUX_URL, SHELFMARK_URL, SPOTIZERR_URL, BUDGET_URL, TASKS_URL, BRAIN_URL,
)


def get_db():
    conn = sqlite3.connect(str(DB_PATH))
    conn.row_factory = sqlite3.Row
    conn.execute("PRAGMA foreign_keys = ON")
    conn.execute("PRAGMA journal_mode = WAL")
    return conn


def init_db():
    conn = get_db()
    c = conn.cursor()

    c.execute('''CREATE TABLE IF NOT EXISTS users (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        username TEXT UNIQUE NOT NULL,
        password_hash TEXT NOT NULL,
        display_name TEXT NOT NULL DEFAULT '',
        created_at TEXT DEFAULT CURRENT_TIMESTAMP
    )''')

    c.execute('''CREATE TABLE IF NOT EXISTS sessions (
        token TEXT PRIMARY KEY,
        user_id INTEGER NOT NULL,
        created_at TEXT DEFAULT CURRENT_TIMESTAMP,
        expires_at TEXT NOT NULL,
        FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
    )''')

    c.execute('''CREATE TABLE IF NOT EXISTS service_connections (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        user_id INTEGER NOT NULL,
        service TEXT NOT NULL,
        auth_type TEXT NOT NULL DEFAULT 'bearer',
        auth_token TEXT NOT NULL,
        metadata TEXT DEFAULT '{}',
        created_at TEXT DEFAULT CURRENT_TIMESTAMP,
        UNIQUE(user_id, service),
        FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
    )''')

    c.execute('''CREATE TABLE IF NOT EXISTS apps (
        id TEXT PRIMARY KEY,
        name TEXT NOT NULL,
        icon TEXT DEFAULT '',
        route_prefix TEXT NOT NULL,
        proxy_target TEXT NOT NULL,
        sort_order INTEGER DEFAULT 0,
        enabled INTEGER DEFAULT 1,
        dashboard_widget TEXT DEFAULT NULL
    )''')

    c.execute('''CREATE TABLE IF NOT EXISTS pinned_items (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        user_id INTEGER NOT NULL,
        service TEXT NOT NULL DEFAULT 'inventory',
        item_id TEXT NOT NULL,
        item_name TEXT NOT NULL DEFAULT '',
        pinned_at TEXT DEFAULT CURRENT_TIMESTAMP,
        UNIQUE(user_id, service, item_id),
        FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
    )''')

    conn.commit()

    # Seed default apps
    existing = c.execute("SELECT COUNT(*) FROM apps").fetchone()[0]
    if existing == 0:
        c.execute("INSERT INTO apps VALUES ('trips', 'Trips', 'map', '/trips', ?, 1, 1, 'upcoming_trips')", (TRIPS_URL,))
        c.execute("INSERT INTO apps VALUES ('fitness', 'Fitness', 'bar-chart', '/fitness', ?, 2, 1, 'daily_calories')", (FITNESS_URL,))
        c.execute("INSERT INTO apps VALUES ('inventory', 'Inventory', 'package', '/inventory', ?, 3, 1, 'items_issues')", (INVENTORY_URL,))
        conn.commit()
    else:
        # Ensure inventory app exists (migration for existing DBs)
        inv = c.execute("SELECT id FROM apps WHERE id = 'inventory'").fetchone()
        if not inv:
            c.execute("INSERT INTO apps VALUES ('inventory', 'Inventory', 'package', '/inventory', ?, 3, 1, 'items_issues')", (INVENTORY_URL,))
            conn.commit()
            print("[Gateway] Added inventory app")

    # Ensure reader app exists
    rdr = c.execute("SELECT id FROM apps WHERE id = 'reader'").fetchone()
    if not rdr:
        c.execute("INSERT INTO apps VALUES ('reader', 'Reader', 'rss', '/reader', ?, 4, 1, 'unread_count')", (MINIFLUX_URL,))
        conn.commit()
        print("[Gateway] Added reader app")

    # Ensure books app exists (now media)
    books = c.execute("SELECT id FROM apps WHERE id = 'books'").fetchone()
    if not books:
        c.execute("INSERT INTO apps VALUES ('books', 'Media', 'book', '/media', ?, 5, 1, NULL)", (SHELFMARK_URL,))
        conn.commit()
        print("[Gateway] Added media app")
    else:
        c.execute("UPDATE apps SET name = 'Media', route_prefix = '/media' WHERE id = 'books'")
        conn.commit()

    # Ensure music (spotizerr) app exists
    music = c.execute("SELECT id FROM apps WHERE id = 'music'").fetchone()
    if not music:
        c.execute("INSERT INTO apps VALUES ('music', 'Music', 'music', '/music', ?, 6, 1, NULL)", (SPOTIZERR_URL,))
        conn.commit()
        print("[Gateway] Added music app")

    # Ensure budget app exists
    budget = c.execute("SELECT id FROM apps WHERE id = 'budget'").fetchone()
    if not budget:
        c.execute("INSERT OR IGNORE INTO apps VALUES ('budget', 'Budget', 'dollar-sign', '/budget', ?, 7, 1, 'budget_summary')", (BUDGET_URL,))
        conn.commit()
        print("[Gateway] Added budget app")

    # Ensure tasks app exists
    tasks = c.execute("SELECT id FROM apps WHERE id = 'tasks'").fetchone()
    if not tasks:
        c.execute("INSERT INTO apps VALUES ('tasks', 'Tasks', 'check-square', '/tasks', ?, 8, 1, 'today_tasks')", (TASKS_URL,))
        conn.commit()
        print("[Gateway] Added tasks app")

    # Ensure brain app exists
    brain = c.execute("SELECT id FROM apps WHERE id = 'brain'").fetchone()
    if not brain:
        c.execute("INSERT INTO apps VALUES ('brain', 'Brain', 'brain', '/brain', ?, 9, 1, NULL)", (BRAIN_URL,))
        conn.commit()
        print("[Gateway] Added brain app")

    # Seed admin user from env vars if no users exist
    import os
    user_count = c.execute("SELECT COUNT(*) FROM users").fetchone()[0]
    if user_count == 0:
        admin_user = os.environ.get("ADMIN_USERNAME")
        admin_pass = os.environ.get("ADMIN_PASSWORD")
        admin_name = os.environ.get("ADMIN_DISPLAY_NAME", "Admin")
        if not admin_user or not admin_pass:
            print("[Gateway] WARNING: No users exist and ADMIN_USERNAME/ADMIN_PASSWORD not set. Create a user manually.")
        else:
            pw_hash = bcrypt.hashpw(admin_pass.encode(), bcrypt.gensalt()).decode()
            c.execute("INSERT INTO users (username, password_hash, display_name) VALUES (?, ?, ?)",
                      (admin_user, pw_hash, admin_name))
            conn.commit()
            print(f"[Gateway] Created admin user: {admin_user}")

    conn.close()
