import initSqlJs, { Database } from 'sql.js';
import { readFileSync, existsSync, mkdirSync, writeFileSync } from 'fs';
import { dirname } from 'path';
import { applyRuntimeMigrations } from './schemaMigrations.js';

let dbInstance: Database | null = null;

/**
 * Initialize and return the database instance
 */
export async function getDatabase(dbPath: string = 'data/recipes.db'): Promise<Database> {
  if (dbInstance) {
    return dbInstance;
  }

  const SQL = await initSqlJs();
  
  // Load existing database or create new one
  if (existsSync(dbPath)) {
    const buffer = readFileSync(dbPath);
    dbInstance = new SQL.Database(buffer);
    applyRuntimeMigrations(dbInstance);
  } else {
    // Create new empty database
    dbInstance = new SQL.Database();
    
    // Apply schema
    const schemaPath = new URL('../db/schema.sql', import.meta.url).pathname;
    const schema = readFileSync(schemaPath, 'utf-8');
    dbInstance.exec(schema);
    applyRuntimeMigrations(dbInstance);
    
    // Ensure data directory exists
    const dir = dirname(dbPath);
    if (!existsSync(dir)) {
      mkdirSync(dir, { recursive: true });
    }
  }

  // Enable foreign key constraints
  dbInstance.run('PRAGMA foreign_keys = ON');

  return dbInstance;
}

/**
 * Save the database to disk
 */
export function saveDatabase(dbPath: string = 'data/recipes.db'): void {
  if (!dbInstance) {
    throw new Error('Database not initialized');
  }

  const data = dbInstance.export();
  const buffer = Buffer.from(data);
  
  // Ensure data directory exists
  const dir = dirname(dbPath);
  if (!existsSync(dir)) {
    mkdirSync(dir, { recursive: true });
  }
  
  // Write to disk
  writeFileSync(dbPath, buffer);
}

/**
 * Get the current database instance (must be initialized first)
 */
export function getDatabaseSync(): Database {
  if (!dbInstance) {
    throw new Error('Database not initialized. Call getDatabase() first.');
  }
  return dbInstance;
}

/**
 * Close the database connection
 */
export function closeDatabase(): void {
  if (dbInstance) {
    dbInstance.close();
    dbInstance = null;
  }
}
