import Database from 'better-sqlite3';
import { drizzle } from 'drizzle-orm/better-sqlite3';
import * as schema from './schema';
import path from 'path';
import fs from 'fs';

// Lazy initialization to avoid database access during build
let _db: ReturnType<typeof drizzle> | null = null;
let _sqlite: Database.Database | null = null;

function getDb() {
  if (!_db) {
    // Ensure data directories exist
    const dataDir = path.join(process.cwd(), 'data');
    const dbDir = path.join(dataDir, 'db');
    const uploadsDir = path.join(dataDir, 'uploads');

    if (!fs.existsSync(dbDir)) {
      fs.mkdirSync(dbDir, { recursive: true });
    }

    if (!fs.existsSync(uploadsDir)) {
      fs.mkdirSync(uploadsDir, { recursive: true });
    }

    // Database file path
    const dbPath = path.join(dbDir, 'wishlist.db');

    // Create SQLite database connection
    _sqlite = new Database(dbPath);
    _sqlite.pragma('journal_mode = WAL'); // Better concurrency

    // Create Drizzle instance
    _db = drizzle(_sqlite, { schema });
  }
  return _db;
}

// Export db as a getter
export const db = new Proxy({} as ReturnType<typeof drizzle>, {
  get(target, prop) {
    return getDb()[prop as keyof ReturnType<typeof drizzle>];
  }
});

// Initialize database (create tables and seed if needed)
export async function initializeDatabase() {
  try {
    // Ensure database is initialized
    const sqlite = _sqlite || getDb() && _sqlite;
    if (!sqlite) throw new Error('Failed to initialize database');

    // Create wishlists table
    sqlite.exec(`
      CREATE TABLE IF NOT EXISTS wishlists (
        id TEXT PRIMARY KEY NOT NULL,
        name TEXT NOT NULL,
        slug TEXT NOT NULL UNIQUE,
        description TEXT,
        preferences TEXT,
        image_url TEXT,
        notes TEXT,
        is_public INTEGER DEFAULT 0 NOT NULL,
        sort_order INTEGER DEFAULT 0 NOT NULL,
        created_at INTEGER DEFAULT (unixepoch()) NOT NULL,
        updated_at INTEGER DEFAULT (unixepoch()) NOT NULL
      )
    `);

    // Create wishlist_items table
    sqlite.exec(`
      CREATE TABLE IF NOT EXISTS wishlist_items (
        id TEXT PRIMARY KEY NOT NULL,
        wishlist_id TEXT NOT NULL,
        name TEXT NOT NULL,
        description TEXT,
        price REAL,
        currency TEXT DEFAULT 'USD' NOT NULL,
        quantity INTEGER DEFAULT 1 NOT NULL,
        images TEXT,
        purchase_urls TEXT,
        notes TEXT,
        is_archived INTEGER DEFAULT 0 NOT NULL,
        claimed_by_name TEXT,
        claimed_by_note TEXT,
        claimed_by_token TEXT UNIQUE,
        claimed_at INTEGER,
        is_purchased INTEGER DEFAULT 0 NOT NULL,
        sort_order INTEGER DEFAULT 0 NOT NULL,
        created_at INTEGER DEFAULT (unixepoch()) NOT NULL,
        updated_at INTEGER DEFAULT (unixepoch()) NOT NULL,
        FOREIGN KEY (wishlist_id) REFERENCES wishlists(id) ON DELETE CASCADE
      )
    `);

    // Create settings table
    sqlite.exec(`
      CREATE TABLE IF NOT EXISTS settings (
        id TEXT PRIMARY KEY NOT NULL,
        key TEXT NOT NULL UNIQUE,
        value TEXT NOT NULL,
        updated_at INTEGER DEFAULT (unixepoch()) NOT NULL
      )
    `);

    // Create guests table
    sqlite.exec(`
      CREATE TABLE IF NOT EXISTS guests (
        id TEXT PRIMARY KEY NOT NULL,
        name TEXT NOT NULL,
        created_at INTEGER DEFAULT (unixepoch()) NOT NULL,
        updated_at INTEGER DEFAULT (unixepoch()) NOT NULL
      )
    `);

    // Create item_claims table
    sqlite.exec(`
      CREATE TABLE IF NOT EXISTS item_claims (
        id TEXT PRIMARY KEY NOT NULL,
        item_id TEXT NOT NULL,
        guest_id TEXT NOT NULL,
        quantity INTEGER DEFAULT 1 NOT NULL,
        note TEXT,
        is_purchased INTEGER DEFAULT 0 NOT NULL,
        claimed_at INTEGER DEFAULT (unixepoch()) NOT NULL,
        updated_at INTEGER DEFAULT (unixepoch()) NOT NULL,
        FOREIGN KEY (item_id) REFERENCES wishlist_items(id) ON DELETE CASCADE,
        FOREIGN KEY (guest_id) REFERENCES guests(id) ON DELETE CASCADE,
        UNIQUE(item_id, guest_id)
      )
    `);
    sqlite.exec('CREATE INDEX IF NOT EXISTS idx_item_claims_item ON item_claims(item_id)');
    sqlite.exec('CREATE INDEX IF NOT EXISTS idx_item_claims_guest ON item_claims(guest_id)');

    // Run migrations for existing databases
    try {
      const columns = sqlite.pragma('table_info(wishlists)') as Array<{ name: string }>;

      // Add image_url column if it doesn't exist
      const hasImageUrl = columns.some((col) => col.name === 'image_url');
      if (!hasImageUrl) {
        sqlite.exec('ALTER TABLE wishlists ADD COLUMN image_url TEXT');
        console.log('✅ Added image_url column to wishlists table');
      }

      // Add sort_order column if it doesn't exist
      const hasSortOrder = columns.some((col) => col.name === 'sort_order');
      if (!hasSortOrder) {
        sqlite.exec('ALTER TABLE wishlists ADD COLUMN sort_order INTEGER DEFAULT 0 NOT NULL');
        console.log('✅ Added sort_order column to wishlists table');
      }

      // Add preferences column if it doesn't exist
      const hasPreferences = columns.some((col) => col.name === 'preferences');
      if (!hasPreferences) {
        sqlite.exec('ALTER TABLE wishlists ADD COLUMN preferences TEXT');
        console.log('✅ Added preferences column to wishlists table');
      }

      const itemColumns = sqlite.pragma('table_info(wishlist_items)') as Array<{ name: string }>;

      const hasClaimedByGuestId = itemColumns.some((col) => col.name === 'claimed_by_guest_id');
      if (!hasClaimedByGuestId) {
        sqlite.exec('ALTER TABLE wishlist_items ADD COLUMN claimed_by_guest_id TEXT REFERENCES guests(id) ON DELETE SET NULL');
        console.log('✅ Added claimed_by_guest_id column to wishlist_items');
      }

      const hasClaimedByName = itemColumns.some((col) => col.name === 'claimed_by_name');
      const hasClaimedByToken = itemColumns.some((col) => col.name === 'claimed_by_token');
      if (hasClaimedByName || hasClaimedByToken) {
        if (hasClaimedByName) {
          sqlite.exec('UPDATE wishlist_items SET claimed_by_name = NULL');
        }
        if (hasClaimedByToken) {
          sqlite.exec('UPDATE wishlist_items SET claimed_by_token = NULL');
        }
        console.log('ℹ️  Legacy claim columns nullified (claimed_by_name / claimed_by_token)');
      }

      // Move any existing inline claims into item_claims (forward-migration), then nullify the inline columns
      const itemColsAfter = sqlite.pragma('table_info(wishlist_items)') as Array<{ name: string }>;
      const stillHasClaimedByGuestId = itemColsAfter.some((c) => c.name === 'claimed_by_guest_id');
      if (stillHasClaimedByGuestId) {
        sqlite.exec(`
          INSERT INTO item_claims (id, item_id, guest_id, quantity, note, is_purchased, claimed_at, updated_at)
          SELECT
            lower(hex(randomblob(16))),
            wi.id,
            wi.claimed_by_guest_id,
            1,
            wi.claimed_by_note,
            wi.is_purchased,
            COALESCE(wi.claimed_at, unixepoch()),
            unixepoch()
          FROM wishlist_items wi
          WHERE wi.claimed_by_guest_id IS NOT NULL
            AND NOT EXISTS (
              SELECT 1 FROM item_claims ic
              WHERE ic.item_id = wi.id AND ic.guest_id = wi.claimed_by_guest_id
            )
        `);
        sqlite.exec('UPDATE wishlist_items SET claimed_by_guest_id = NULL, claimed_by_note = NULL, claimed_at = NULL, is_purchased = 0');
        console.log('ℹ️  Migrated inline claims into item_claims and cleared inline claim columns');
      }
    } catch (migrationError) {
      console.log('Migration already applied or not needed');
    }

    // Auto-seed database if empty
    const { seedDatabase } = await import('./seed');
    await seedDatabase();

    return true;
  } catch (error) {
    console.error('❌ Database initialization failed:', error);
    throw error;
  }
}

// Export schema for use in other files
export * from './schema';
