import type { Knex } from 'knex';

export async function up(knex: Knex): Promise<void> {
  // Users table for email/password authentication
  await knex.schema.createTable('users', table => {
    table.uuid('id').primary().defaultTo(knex.raw('uuid_generate_v4()'));
    table.string('email', 255).notNullable().unique();
    table.string('password_hash', 255).notNullable();
    table.string('name', 255).notNullable();
    table.enum('role', ['ADMIN', 'DEPARTMENT', 'CITIZEN']).notNullable();
    table.uuid('department_id').references('id').inTable('departments').onDelete('SET NULL');
    table.string('wallet_address', 42);
    table.text('wallet_encrypted_key');
    table.string('phone', 20);
    table.boolean('is_active').notNullable().defaultTo(true);
    table.timestamp('last_login_at');
    table.timestamp('created_at').notNullable().defaultTo(knex.fn.now());
    table.timestamp('updated_at').notNullable().defaultTo(knex.fn.now());

    table.index('email', 'idx_user_email');
    table.index('role', 'idx_user_role');
    table.index('department_id', 'idx_user_department');
    table.index('is_active', 'idx_user_active');
  });

  // Wallets table for storing encrypted private keys
  await knex.schema.createTable('wallets', table => {
    table.uuid('id').primary().defaultTo(knex.raw('uuid_generate_v4()'));
    table.string('address', 42).notNullable().unique();
    table.text('encrypted_private_key').notNullable();
    table.enum('owner_type', ['USER', 'DEPARTMENT']).notNullable();
    table.uuid('owner_id').notNullable();
    table.boolean('is_active').notNullable().defaultTo(true);
    table.timestamp('created_at').notNullable().defaultTo(knex.fn.now());
    table.timestamp('updated_at').notNullable().defaultTo(knex.fn.now());

    table.index('address', 'idx_wallet_address');
    table.index(['owner_type', 'owner_id'], 'idx_wallet_owner');
  });

  // Blockchain events table
  await knex.schema.createTable('blockchain_events', table => {
    table.uuid('id').primary().defaultTo(knex.raw('uuid_generate_v4()'));
    table.string('tx_hash', 66).notNullable();
    table.string('event_name', 100).notNullable();
    table.string('contract_address', 42).notNullable();
    table.bigInteger('block_number').notNullable();
    table.integer('log_index').notNullable();
    table.jsonb('args').notNullable();
    table.jsonb('decoded_args');
    table.string('related_entity_type', 50);
    table.uuid('related_entity_id');
    table.timestamp('created_at').notNullable().defaultTo(knex.fn.now());

    table.unique(['tx_hash', 'log_index'], { indexName: 'uq_event_tx_log' });
    table.index('tx_hash', 'idx_event_tx');
    table.index('event_name', 'idx_event_name');
    table.index('contract_address', 'idx_event_contract');
    table.index('block_number', 'idx_event_block');
    table.index('created_at', 'idx_event_created');
    table.index(['related_entity_type', 'related_entity_id'], 'idx_event_entity');
  });

  // Application logs table
  await knex.schema.createTable('application_logs', table => {
    table.uuid('id').primary().defaultTo(knex.raw('uuid_generate_v4()'));
    table.enum('level', ['DEBUG', 'INFO', 'WARN', 'ERROR']).notNullable();
    table.string('module', 100).notNullable();
    table.text('message').notNullable();
    table.jsonb('context');
    table.text('stack_trace');
    table.uuid('user_id');
    table.string('correlation_id', 100);
    table.string('ip_address', 45);
    table.text('user_agent');
    table.timestamp('created_at').notNullable().defaultTo(knex.fn.now());

    table.index('level', 'idx_applog_level');
    table.index('module', 'idx_applog_module');
    table.index('user_id', 'idx_applog_user');
    table.index('correlation_id', 'idx_applog_correlation');
    table.index('created_at', 'idx_applog_created');
  });

  // Add additional fields to departments table
  await knex.schema.alterTable('departments', table => {
    table.text('description');
    table.string('contact_email', 255);
    table.string('contact_phone', 20);
    table.timestamp('last_webhook_at');
  });
}

export async function down(knex: Knex): Promise<void> {
  // Remove additional fields from departments
  await knex.schema.alterTable('departments', table => {
    table.dropColumn('description');
    table.dropColumn('contact_email');
    table.dropColumn('contact_phone');
    table.dropColumn('last_webhook_at');
  });

  await knex.schema.dropTableIfExists('application_logs');
  await knex.schema.dropTableIfExists('blockchain_events');
  await knex.schema.dropTableIfExists('wallets');
  await knex.schema.dropTableIfExists('users');
}
