import type { Knex } from 'knex';

export async function up(knex: Knex): Promise<void> {
  // Enable UUID extension
  await knex.raw('CREATE EXTENSION IF NOT EXISTS "uuid-ossp"');

  // Applicants table
  await knex.schema.createTable('applicants', table => {
    table.uuid('id').primary().defaultTo(knex.raw('uuid_generate_v4()'));
    table.string('digilocker_id', 255).notNullable().unique();
    table.string('name', 255).notNullable();
    table.string('email', 255).notNullable();
    table.string('phone', 20);
    table.string('wallet_address', 42);
    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('digilocker_id', 'idx_applicant_digilocker');
    table.index('email', 'idx_applicant_email');
  });

  // Departments table
  await knex.schema.createTable('departments', table => {
    table.uuid('id').primary().defaultTo(knex.raw('uuid_generate_v4()'));
    table.string('code', 50).notNullable().unique();
    table.string('name', 255).notNullable();
    table.string('wallet_address', 42).unique();
    table.string('api_key_hash', 255);
    table.string('api_secret_hash', 255);
    table.string('webhook_url', 500);
    table.string('webhook_secret_hash', 255);
    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('code', 'idx_department_code');
    table.index('is_active', 'idx_department_active');
  });

  // Workflows table
  await knex.schema.createTable('workflows', table => {
    table.uuid('id').primary().defaultTo(knex.raw('uuid_generate_v4()'));
    table.string('workflow_type', 100).notNullable().unique();
    table.string('name', 255).notNullable();
    table.text('description');
    table.integer('version').notNullable().defaultTo(1);
    table.jsonb('definition').notNullable();
    table.boolean('is_active').notNullable().defaultTo(true);
    table.uuid('created_by');
    table.timestamp('created_at').notNullable().defaultTo(knex.fn.now());
    table.timestamp('updated_at').notNullable().defaultTo(knex.fn.now());

    table.index('workflow_type', 'idx_workflow_type');
    table.index('is_active', 'idx_workflow_active');
  });

  // License Requests table
  await knex.schema.createTable('license_requests', table => {
    table.uuid('id').primary().defaultTo(knex.raw('uuid_generate_v4()'));
    table.string('request_number', 50).notNullable().unique();
    table.bigInteger('token_id');
    table
      .uuid('applicant_id')
      .notNullable()
      .references('id')
      .inTable('applicants')
      .onDelete('CASCADE');
    table.string('request_type', 100).notNullable();
    table.uuid('workflow_id').references('id').inTable('workflows').onDelete('SET NULL');
    table.string('status', 50).notNullable().defaultTo('DRAFT');
    table.jsonb('metadata');
    table.string('current_stage_id', 100);
    table.string('blockchain_tx_hash', 66);
    table.timestamp('created_at').notNullable().defaultTo(knex.fn.now());
    table.timestamp('updated_at').notNullable().defaultTo(knex.fn.now());
    table.timestamp('submitted_at');
    table.timestamp('approved_at');

    table.index('request_number', 'idx_request_number');
    table.index('applicant_id', 'idx_request_applicant');
    table.index('status', 'idx_request_status');
    table.index('request_type', 'idx_request_type');
    table.index('created_at', 'idx_request_created');
    table.index(['status', 'request_type'], 'idx_request_status_type');
  });

  // Documents table
  await knex.schema.createTable('documents', table => {
    table.uuid('id').primary().defaultTo(knex.raw('uuid_generate_v4()'));
    table
      .uuid('request_id')
      .notNullable()
      .references('id')
      .inTable('license_requests')
      .onDelete('CASCADE');
    table.string('doc_type', 100).notNullable();
    table.string('original_filename', 255).notNullable();
    table.integer('current_version').notNullable().defaultTo(1);
    table.string('current_hash', 66).notNullable();
    table.string('minio_bucket', 100).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('request_id', 'idx_document_request');
    table.index('doc_type', 'idx_document_type');
  });

  // Document Versions table
  await knex.schema.createTable('document_versions', table => {
    table.uuid('id').primary().defaultTo(knex.raw('uuid_generate_v4()'));
    table
      .uuid('document_id')
      .notNullable()
      .references('id')
      .inTable('documents')
      .onDelete('CASCADE');
    table.integer('version').notNullable();
    table.string('hash', 66).notNullable();
    table.string('minio_path', 500).notNullable();
    table.bigInteger('file_size').notNullable();
    table.string('mime_type', 100).notNullable();
    table.uuid('uploaded_by').notNullable();
    table.string('blockchain_tx_hash', 66);
    table.timestamp('created_at').notNullable().defaultTo(knex.fn.now());

    table.unique(['document_id', 'version'], { indexName: 'uq_document_version' });
    table.index('document_id', 'idx_docversion_document');
  });

  // Approvals table
  await knex.schema.createTable('approvals', table => {
    table.uuid('id').primary().defaultTo(knex.raw('uuid_generate_v4()'));
    table
      .uuid('request_id')
      .notNullable()
      .references('id')
      .inTable('license_requests')
      .onDelete('CASCADE');
    table
      .uuid('department_id')
      .notNullable()
      .references('id')
      .inTable('departments')
      .onDelete('CASCADE');
    table.string('status', 50).notNullable().defaultTo('PENDING');
    table.text('remarks');
    table.string('remarks_hash', 66);
    table.jsonb('reviewed_documents');
    table.string('blockchain_tx_hash', 66);
    table.boolean('is_active').notNullable().defaultTo(true);
    table.timestamp('invalidated_at');
    table.string('invalidation_reason', 255);
    table.timestamp('created_at').notNullable().defaultTo(knex.fn.now());
    table.timestamp('updated_at').notNullable().defaultTo(knex.fn.now());

    table.index('request_id', 'idx_approval_request');
    table.index('department_id', 'idx_approval_department');
    table.index('status', 'idx_approval_status');
    table.index(['request_id', 'department_id'], 'idx_approval_request_dept');
  });

  // Workflow States table
  await knex.schema.createTable('workflow_states', table => {
    table.uuid('id').primary().defaultTo(knex.raw('uuid_generate_v4()'));
    table
      .uuid('request_id')
      .notNullable()
      .unique()
      .references('id')
      .inTable('license_requests')
      .onDelete('CASCADE');
    table.string('current_stage_id', 100).notNullable();
    table.jsonb('completed_stages').notNullable().defaultTo('[]');
    table.jsonb('pending_approvals').notNullable().defaultTo('[]');
    table.jsonb('execution_log').notNullable().defaultTo('[]');
    table.timestamp('stage_started_at');
    table.timestamp('created_at').notNullable().defaultTo(knex.fn.now());
    table.timestamp('updated_at').notNullable().defaultTo(knex.fn.now());

    table.index('request_id', 'idx_wfstate_request');
  });

  // Webhooks table
  await knex.schema.createTable('webhooks', table => {
    table.uuid('id').primary().defaultTo(knex.raw('uuid_generate_v4()'));
    table
      .uuid('department_id')
      .notNullable()
      .references('id')
      .inTable('departments')
      .onDelete('CASCADE');
    table.string('url', 500).notNullable();
    table.jsonb('events').notNullable();
    table.string('secret_hash', 255).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('department_id', 'idx_webhook_department');
  });

  // Webhook Logs table
  await knex.schema.createTable('webhook_logs', table => {
    table.uuid('id').primary().defaultTo(knex.raw('uuid_generate_v4()'));
    table.uuid('webhook_id').notNullable().references('id').inTable('webhooks').onDelete('CASCADE');
    table.string('event_type', 100).notNullable();
    table.jsonb('payload').notNullable();
    table.integer('response_status');
    table.text('response_body');
    table.integer('response_time');
    table.integer('retry_count').notNullable().defaultTo(0);
    table.string('status', 20).notNullable().defaultTo('PENDING');
    table.timestamp('created_at').notNullable().defaultTo(knex.fn.now());

    table.index('webhook_id', 'idx_webhooklog_webhook');
    table.index('event_type', 'idx_webhooklog_event');
    table.index('status', 'idx_webhooklog_status');
    table.index('created_at', 'idx_webhooklog_created');
  });

  // Audit Logs table
  await knex.schema.createTable('audit_logs', table => {
    table.uuid('id').primary().defaultTo(knex.raw('uuid_generate_v4()'));
    table.string('entity_type', 50).notNullable();
    table.uuid('entity_id').notNullable();
    table.string('action', 50).notNullable();
    table.string('actor_type', 50).notNullable();
    table.uuid('actor_id');
    table.jsonb('old_value');
    table.jsonb('new_value');
    table.string('ip_address', 45);
    table.text('user_agent');
    table.string('correlation_id', 100);
    table.timestamp('created_at').notNullable().defaultTo(knex.fn.now());

    table.index(['entity_type', 'entity_id'], 'idx_audit_entity');
    table.index('entity_type', 'idx_audit_entitytype');
    table.index('action', 'idx_audit_action');
    table.index('created_at', 'idx_audit_created');
    table.index('correlation_id', 'idx_audit_correlation');
  });

  // Blockchain Transactions table
  await knex.schema.createTable('blockchain_transactions', table => {
    table.uuid('id').primary().defaultTo(knex.raw('uuid_generate_v4()'));
    table.string('tx_hash', 66).notNullable().unique();
    table.string('tx_type', 50).notNullable();
    table.string('related_entity_type', 50).notNullable();
    table.uuid('related_entity_id').notNullable();
    table.string('from_address', 42).notNullable();
    table.string('to_address', 42);
    table.string('status', 20).notNullable().defaultTo('PENDING');
    table.bigInteger('block_number');
    table.bigInteger('gas_used');
    table.text('error_message');
    table.timestamp('created_at').notNullable().defaultTo(knex.fn.now());
    table.timestamp('confirmed_at');

    table.index('tx_hash', 'idx_bctx_hash');
    table.index('tx_type', 'idx_bctx_type');
    table.index('status', 'idx_bctx_status');
    table.index('related_entity_id', 'idx_bctx_entity');
    table.index('created_at', 'idx_bctx_created');
  });
}

export async function down(knex: Knex): Promise<void> {
  await knex.schema.dropTableIfExists('blockchain_transactions');
  await knex.schema.dropTableIfExists('audit_logs');
  await knex.schema.dropTableIfExists('webhook_logs');
  await knex.schema.dropTableIfExists('webhooks');
  await knex.schema.dropTableIfExists('workflow_states');
  await knex.schema.dropTableIfExists('approvals');
  await knex.schema.dropTableIfExists('document_versions');
  await knex.schema.dropTableIfExists('documents');
  await knex.schema.dropTableIfExists('license_requests');
  await knex.schema.dropTableIfExists('workflows');
  await knex.schema.dropTableIfExists('departments');
  await knex.schema.dropTableIfExists('applicants');
}
