import * as SQLite from 'expo-sqlite';
import { CREATE_TABLES, SCHEMA_VERSION } from './schema';

let db: SQLite.SQLiteDatabase | null = null;

/**
 * Open or create the database
 */
export async function openDatabase(): Promise<SQLite.SQLiteDatabase> {
  if (db) {
    return db;
  }

  db = await SQLite.openDatabaseAsync('pottery_diary.db');

  // Enable foreign keys
  await db.execAsync('PRAGMA foreign_keys = ON;');

  // Check schema version
  try {
    const result = await db.getFirstAsync<{ user_version: number }>(
      'PRAGMA user_version;'
    );
    const currentVersion = result?.user_version || 0;

    if (currentVersion < SCHEMA_VERSION) {
      await migrateDatabase(db, currentVersion);
    }
  } catch (error) {
    console.error('Error checking schema version:', error);
    throw error;
  }

  return db;
}

/**
 * Run database migrations
 */
async function migrateDatabase(
  database: SQLite.SQLiteDatabase,
  fromVersion: number
): Promise<void> {
  console.log(`Migrating database from version ${fromVersion} to ${SCHEMA_VERSION}`);

  if (fromVersion === 0) {
    // Initial schema creation
    await database.execAsync(CREATE_TABLES);
    await database.execAsync(`PRAGMA user_version = ${SCHEMA_VERSION};`);
    return;
  }

  // Migration from v1 to v2: Add color column to glazes
  if (fromVersion < 2) {
    console.log('Migrating to version 2: Dropping and recreating tables with color column');
    // Drop all tables and recreate with new schema
    await database.execAsync(`
      DROP TABLE IF EXISTS step_glazes;
      DROP TABLE IF EXISTS steps;
      DROP TABLE IF EXISTS projects;
      DROP TABLE IF EXISTS glazes;
      DROP TABLE IF EXISTS settings;
    `);
    await database.execAsync(CREATE_TABLES);
    await database.execAsync(`PRAGMA user_version = 2;`);
    console.log('Migration to version 2 complete');
  }

  // Migration from v2 to v3: Re-seed glazes with 125 glazes
  if (fromVersion < 3) {
    console.log('Migrating to version 3: Clearing and re-seeding glaze catalog');
    // Just delete all glazes and they will be re-seeded on next app init
    await database.execAsync(`DELETE FROM glazes;`);
    await database.execAsync(`PRAGMA user_version = 3;`);
    console.log('Migration to version 3 complete');
  }

  // Migration from v3 to v4: Add mixed glaze support
  if (fromVersion < 4) {
    console.log('Migrating to version 4: Adding mixed glaze columns');
    await database.execAsync(`
      ALTER TABLE glazes ADD COLUMN is_mix INTEGER NOT NULL DEFAULT 0;
      ALTER TABLE glazes ADD COLUMN mixed_glaze_ids TEXT;
      ALTER TABLE glazes ADD COLUMN mix_ratio TEXT;
    `);
    await database.execAsync(`PRAGMA user_version = 4;`);
    console.log('Migration to version 4 complete');
  }

  // Migration from v4 to v5: Add mix_notes to glazing_fields
  if (fromVersion < 5) {
    console.log('Migrating to version 5: Adding mix_notes to glazing_fields');
    await database.execAsync(`
      ALTER TABLE glazing_fields ADD COLUMN mix_notes TEXT;
    `);
    await database.execAsync(`PRAGMA user_version = 5;`);
    console.log('Migration to version 5 complete');
  }

  // Migration from v5 to v6: Fix steps table to include 'trimming' type
  if (fromVersion < 6) {
    console.log('Migrating to version 6: Recreating steps table with trimming type');
    // SQLite doesn't support modifying CHECK constraints, so we need to recreate the table
    await database.execAsync(`
      -- Create new table with correct constraint
      CREATE TABLE steps_new (
        id TEXT PRIMARY KEY NOT NULL,
        project_id TEXT NOT NULL,
        type TEXT NOT NULL CHECK(type IN ('forming', 'trimming', 'drying', 'bisque_firing', 'glazing', 'glaze_firing', 'misc')),
        notes_markdown TEXT,
        photo_uris TEXT NOT NULL,
        created_at TEXT NOT NULL,
        updated_at TEXT NOT NULL,
        FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
      );

      -- Copy data from old table
      INSERT INTO steps_new SELECT * FROM steps;

      -- Drop old table
      DROP TABLE steps;

      -- Rename new table
      ALTER TABLE steps_new RENAME TO steps;

      -- Recreate indexes
      CREATE INDEX IF NOT EXISTS idx_steps_project_id ON steps(project_id);
      CREATE INDEX IF NOT EXISTS idx_steps_type ON steps(type);
    `);
    await database.execAsync(`PRAGMA user_version = 6;`);
    console.log('Migration to version 6 complete - trimming type now supported');
  }

  // Migration from v6 to v7: Add user_id columns for multi-user support
  if (fromVersion < 7) {
    console.log('Migrating to version 7: Adding user_id columns for multi-user support');

    // For simplicity during development, we'll drop and recreate all tables
    // In production, you'd want to preserve data and migrate it properly
    await database.execAsync(`
      -- Drop all tables
      DROP TABLE IF EXISTS firing_fields;
      DROP TABLE IF EXISTS glazing_fields;
      DROP TABLE IF EXISTS steps;
      DROP TABLE IF EXISTS projects;
      DROP TABLE IF EXISTS glazes;
      DROP TABLE IF EXISTS settings;
      DROP TABLE IF EXISTS news_items;
    `);

    // Recreate with new schema
    await database.execAsync(CREATE_TABLES);
    await database.execAsync(`PRAGMA user_version = 7;`);
    console.log('Migration to version 7 complete - multi-user support added');
    console.log('Note: All existing data was cleared. Glazes will be re-seeded.');
  }

  // Migration from v7 to v8: Add enhanced features
  if (fromVersion < 8) {
    console.log('Migrating to version 8: Adding enhanced pottery workflow features');

    // Add weight_unit to settings
    await database.execAsync(`
      ALTER TABLE settings ADD COLUMN weight_unit TEXT NOT NULL DEFAULT 'lb' CHECK(weight_unit IN ('lb', 'oz', 'kg', 'g'));
    `);

    // Add kiln fields to firing_fields
    await database.execAsync(`
      ALTER TABLE firing_fields ADD COLUMN kiln_type TEXT CHECK(kiln_type IN ('electric', 'gas', 'raku', 'other'));
      ALTER TABLE firing_fields ADD COLUMN kiln_custom_name TEXT;
      ALTER TABLE firing_fields ADD COLUMN kiln_position TEXT CHECK(kiln_position IN ('top', 'middle', 'bottom', 'other'));
      ALTER TABLE firing_fields ADD COLUMN kiln_position_notes TEXT;
      ALTER TABLE firing_fields ADD COLUMN firing_schedule TEXT;
    `);

    // Add glaze_layers to glazing_fields for multi-layer support
    await database.execAsync(`
      ALTER TABLE glazing_fields ADD COLUMN glaze_layers TEXT;
    `);

    // Create user_lists table
    await database.execAsync(`
      CREATE TABLE IF NOT EXISTS user_lists (
        id TEXT PRIMARY KEY NOT NULL,
        user_id TEXT NOT NULL,
        type TEXT NOT NULL CHECK(type IN ('shopping', 'wish')),
        item TEXT NOT NULL,
        notes TEXT,
        is_completed INTEGER NOT NULL DEFAULT 0,
        created_at TEXT NOT NULL,
        FOREIGN KEY (user_id) REFERENCES settings(user_id)
      );

      CREATE INDEX IF NOT EXISTS idx_user_lists_user_id ON user_lists(user_id);
      CREATE INDEX IF NOT EXISTS idx_user_lists_type ON user_lists(type);
    `);

    // Create forming_fields table
    await database.execAsync(`
      CREATE TABLE IF NOT EXISTS forming_fields (
        step_id TEXT PRIMARY KEY NOT NULL,
        clay_body TEXT,
        clay_weight_value REAL,
        clay_weight_unit TEXT CHECK(clay_weight_unit IN ('lb', 'oz', 'kg', 'g')),
        production_method TEXT CHECK(production_method IN ('wheel', 'handbuilding', 'casting', 'other')),
        dimensions TEXT,
        FOREIGN KEY (step_id) REFERENCES steps(id) ON DELETE CASCADE
      );
    `);

    await database.execAsync(`PRAGMA user_version = 8;`);
    console.log('Migration to version 8 complete - Enhanced pottery workflow features added');
  }
}

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

/**
 * Get the current database instance
 */
export function getDatabase(): SQLite.SQLiteDatabase {
  if (!db) {
    throw new Error('Database not initialized. Call openDatabase() first.');
  }
  return db;
}

/**
 * Execute a transaction
 */
export async function runTransaction(
  callback: (tx: SQLite.SQLiteDatabase) => Promise<void>
): Promise<void> {
  const database = getDatabase();
  try {
    await database.execAsync('BEGIN TRANSACTION;');
    await callback(database);
    await database.execAsync('COMMIT;');
  } catch (error) {
    await database.execAsync('ROLLBACK;');
    throw error;
  }
}
