/**
 * Local SQLite database for offline card hash caching.
 * Syncs with Convex and provides offline recognition support.
 */

import * as SQLite from "expo-sqlite";
import type { CardHashEntry } from "../recognition";

const DB_NAME = "scry_cache.db";

let db: SQLite.SQLiteDatabase | null = null;

/**
 * Initialize the local database.
 */
export async function initDatabase(): Promise<void> {
  if (db) return;
  
  db = await SQLite.openDatabaseAsync(DB_NAME);
  
  // Create tables
  await db.execAsync(`
    CREATE TABLE IF NOT EXISTS cards (
      scryfall_id TEXT PRIMARY KEY,
      oracle_id TEXT NOT NULL,
      name TEXT NOT NULL,
      set_code TEXT NOT NULL,
      collector_number TEXT,
      rarity TEXT,
      artist TEXT,
      image_uri TEXT,
      hash BLOB NOT NULL,
      hash_version INTEGER DEFAULT 1,
      updated_at INTEGER NOT NULL
    );
    
    CREATE TABLE IF NOT EXISTS sync_metadata (
      key TEXT PRIMARY KEY,
      value TEXT NOT NULL
    );
    
    CREATE INDEX IF NOT EXISTS idx_cards_name ON cards(name);
    CREATE INDEX IF NOT EXISTS idx_cards_updated ON cards(updated_at);
  `);
  
  console.log("[LocalDB] Database initialized");
}

/**
 * Get the last sync timestamp.
 */
export async function getLastSyncTimestamp(): Promise<number> {
  if (!db) await initDatabase();
  
  const result = await db!.getFirstAsync<{ value: string }>(
    "SELECT value FROM sync_metadata WHERE key = ?",
    ["last_sync"]
  );
  
  return result ? parseInt(result.value, 10) : 0;
}

/**
 * Set the last sync timestamp.
 */
export async function setLastSyncTimestamp(timestamp: number): Promise<void> {
  if (!db) await initDatabase();
  
  await db!.runAsync(
    "INSERT OR REPLACE INTO sync_metadata (key, value) VALUES (?, ?)",
    ["last_sync", timestamp.toString()]
  );
}

/**
 * Get all cached card hashes for recognition.
 */
export async function getCachedHashes(): Promise<CardHashEntry[]> {
  if (!db) await initDatabase();
  
  const rows = await db!.getAllAsync<{
    scryfall_id: string;
    name: string;
    set_code: string;
    collector_number: string | null;
    image_uri: string | null;
    hash: Uint8Array;
  }>("SELECT scryfall_id, name, set_code, collector_number, image_uri, hash FROM cards");
  
  return rows.map((row) => ({
    id: row.scryfall_id,
    name: row.name,
    setCode: row.set_code,
    collectorNumber: row.collector_number || undefined,
    imageUri: row.image_uri || undefined,
    hash: new Uint8Array(row.hash),
  }));
}

/**
 * Get the count of cached cards.
 */
export async function getCachedCardCount(): Promise<number> {
  if (!db) await initDatabase();
  
  const result = await db!.getFirstAsync<{ count: number }>(
    "SELECT COUNT(*) as count FROM cards"
  );
  
  return result?.count || 0;
}

/**
 * Insert or update cards from Convex.
 */
export async function upsertCards(cards: Array<{
  scryfallId: string;
  oracleId: string;
  name: string;
  setCode: string;
  collectorNumber: string;
  rarity: string;
  artist?: string;
  imageUri?: string;
  hash: Uint8Array;
  hashVersion: number;
  updatedAt: number;
}>): Promise<void> {
  if (!db) await initDatabase();
  
  // Use a transaction for batch insert
  await db!.withTransactionAsync(async () => {
    for (const card of cards) {
      await db!.runAsync(
        `INSERT OR REPLACE INTO cards 
         (scryfall_id, oracle_id, name, set_code, collector_number, rarity, artist, image_uri, hash, hash_version, updated_at)
         VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
        [
          card.scryfallId,
          card.oracleId,
          card.name,
          card.setCode,
          card.collectorNumber,
          card.rarity,
          card.artist || null,
          card.imageUri || null,
          card.hash,
          card.hashVersion,
          card.updatedAt,
        ]
      );
    }
  });
  
  console.log(`[LocalDB] Upserted ${cards.length} cards`);
}

/**
 * Clear all cached data.
 */
export async function clearCache(): Promise<void> {
  if (!db) await initDatabase();
  
  await db!.execAsync(`
    DELETE FROM cards;
    DELETE FROM sync_metadata;
  `);
  
  console.log("[LocalDB] Cache cleared");
}

/**
 * Close the database connection.
 */
export async function closeDatabase(): Promise<void> {
  if (db) {
    await db.closeAsync();
    db = null;
  }
}
