-- Enable UUID extension
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";

-- =============================================
-- MIGRATION 1: Initial Schema
-- =============================================

-- Applicants table
CREATE TABLE IF NOT EXISTS applicants (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  digilocker_id VARCHAR(255) NOT NULL UNIQUE,
  name VARCHAR(255) NOT NULL,
  email VARCHAR(255) NOT NULL,
  phone VARCHAR(20),
  wallet_address VARCHAR(42),
  is_active BOOLEAN NOT NULL DEFAULT true,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_applicant_digilocker ON applicants(digilocker_id);
CREATE INDEX IF NOT EXISTS idx_applicant_email ON applicants(email);

-- Departments table
CREATE TABLE IF NOT EXISTS departments (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  code VARCHAR(50) NOT NULL UNIQUE,
  name VARCHAR(255) NOT NULL,
  wallet_address VARCHAR(42) UNIQUE,
  api_key_hash VARCHAR(255),
  api_secret_hash VARCHAR(255),
  webhook_url VARCHAR(500),
  webhook_secret_hash VARCHAR(255),
  is_active BOOLEAN NOT NULL DEFAULT true,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  description TEXT,
  contact_email VARCHAR(255),
  contact_phone VARCHAR(20),
  last_webhook_at TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_department_code ON departments(code);
CREATE INDEX IF NOT EXISTS idx_department_active ON departments(is_active);

-- Workflows table
CREATE TABLE IF NOT EXISTS workflows (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  workflow_type VARCHAR(100) NOT NULL UNIQUE,
  name VARCHAR(255) NOT NULL,
  description TEXT,
  version INTEGER NOT NULL DEFAULT 1,
  definition JSONB NOT NULL,
  is_active BOOLEAN NOT NULL DEFAULT true,
  created_by UUID,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_workflow_type ON workflows(workflow_type);
CREATE INDEX IF NOT EXISTS idx_workflow_active ON workflows(is_active);

-- License Requests table
CREATE TABLE IF NOT EXISTS license_requests (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  request_number VARCHAR(50) NOT NULL UNIQUE,
  token_id BIGINT,
  applicant_id UUID NOT NULL REFERENCES applicants(id) ON DELETE CASCADE,
  request_type VARCHAR(100) NOT NULL,
  workflow_id UUID REFERENCES workflows(id) ON DELETE SET NULL,
  status VARCHAR(50) NOT NULL DEFAULT 'DRAFT',
  metadata JSONB,
  current_stage_id VARCHAR(100),
  blockchain_tx_hash VARCHAR(66),
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  submitted_at TIMESTAMP,
  approved_at TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_request_number ON license_requests(request_number);
CREATE INDEX IF NOT EXISTS idx_request_applicant ON license_requests(applicant_id);
CREATE INDEX IF NOT EXISTS idx_request_status ON license_requests(status);
CREATE INDEX IF NOT EXISTS idx_request_type ON license_requests(request_type);
CREATE INDEX IF NOT EXISTS idx_request_created ON license_requests(created_at);
CREATE INDEX IF NOT EXISTS idx_request_status_type ON license_requests(status, request_type);

-- Documents table
CREATE TABLE IF NOT EXISTS documents (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  request_id UUID NOT NULL REFERENCES license_requests(id) ON DELETE CASCADE,
  doc_type VARCHAR(100) NOT NULL,
  original_filename VARCHAR(255) NOT NULL,
  current_version INTEGER NOT NULL DEFAULT 1,
  current_hash VARCHAR(66) NOT NULL,
  minio_bucket VARCHAR(100) NOT NULL,
  is_active BOOLEAN NOT NULL DEFAULT true,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_document_request ON documents(request_id);
CREATE INDEX IF NOT EXISTS idx_document_type ON documents(doc_type);

-- Document Versions table
CREATE TABLE IF NOT EXISTS document_versions (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  document_id UUID NOT NULL REFERENCES documents(id) ON DELETE CASCADE,
  version INTEGER NOT NULL,
  hash VARCHAR(66) NOT NULL,
  minio_path VARCHAR(500) NOT NULL,
  file_size BIGINT NOT NULL,
  mime_type VARCHAR(100) NOT NULL,
  uploaded_by UUID NOT NULL,
  blockchain_tx_hash VARCHAR(66),
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  UNIQUE(document_id, version)
);
CREATE INDEX IF NOT EXISTS idx_docversion_document ON document_versions(document_id);

-- Approvals table
CREATE TABLE IF NOT EXISTS approvals (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  request_id UUID NOT NULL REFERENCES license_requests(id) ON DELETE CASCADE,
  department_id UUID NOT NULL REFERENCES departments(id) ON DELETE CASCADE,
  status VARCHAR(50) NOT NULL DEFAULT 'PENDING',
  remarks TEXT,
  remarks_hash VARCHAR(66),
  reviewed_documents JSONB,
  blockchain_tx_hash VARCHAR(66),
  is_active BOOLEAN NOT NULL DEFAULT true,
  invalidated_at TIMESTAMP,
  invalidation_reason VARCHAR(255),
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_approval_request ON approvals(request_id);
CREATE INDEX IF NOT EXISTS idx_approval_department ON approvals(department_id);
CREATE INDEX IF NOT EXISTS idx_approval_status ON approvals(status);
CREATE INDEX IF NOT EXISTS idx_approval_request_dept ON approvals(request_id, department_id);

-- Workflow States table
CREATE TABLE IF NOT EXISTS workflow_states (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  request_id UUID NOT NULL UNIQUE REFERENCES license_requests(id) ON DELETE CASCADE,
  current_stage_id VARCHAR(100) NOT NULL,
  completed_stages JSONB NOT NULL DEFAULT '[]',
  pending_approvals JSONB NOT NULL DEFAULT '[]',
  execution_log JSONB NOT NULL DEFAULT '[]',
  stage_started_at TIMESTAMP,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_wfstate_request ON workflow_states(request_id);

-- Webhooks table
CREATE TABLE IF NOT EXISTS webhooks (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  department_id UUID NOT NULL REFERENCES departments(id) ON DELETE CASCADE,
  url VARCHAR(500) NOT NULL,
  events JSONB NOT NULL,
  secret_hash VARCHAR(255) NOT NULL,
  is_active BOOLEAN NOT NULL DEFAULT true,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_webhook_department ON webhooks(department_id);

-- Webhook Logs table
CREATE TABLE IF NOT EXISTS webhook_logs (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  webhook_id UUID NOT NULL REFERENCES webhooks(id) ON DELETE CASCADE,
  event_type VARCHAR(100) NOT NULL,
  payload JSONB NOT NULL,
  response_status INTEGER,
  response_body TEXT,
  response_time INTEGER,
  retry_count INTEGER NOT NULL DEFAULT 0,
  status VARCHAR(20) NOT NULL DEFAULT 'PENDING',
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_webhooklog_webhook ON webhook_logs(webhook_id);
CREATE INDEX IF NOT EXISTS idx_webhooklog_event ON webhook_logs(event_type);
CREATE INDEX IF NOT EXISTS idx_webhooklog_status ON webhook_logs(status);
CREATE INDEX IF NOT EXISTS idx_webhooklog_created ON webhook_logs(created_at);

-- Audit Logs table
CREATE TABLE IF NOT EXISTS audit_logs (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  entity_type VARCHAR(50) NOT NULL,
  entity_id UUID NOT NULL,
  action VARCHAR(50) NOT NULL,
  actor_type VARCHAR(50) NOT NULL,
  actor_id UUID,
  old_value JSONB,
  new_value JSONB,
  ip_address VARCHAR(45),
  user_agent TEXT,
  correlation_id VARCHAR(100),
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_audit_entity ON audit_logs(entity_type, entity_id);
CREATE INDEX IF NOT EXISTS idx_audit_entitytype ON audit_logs(entity_type);
CREATE INDEX IF NOT EXISTS idx_audit_action ON audit_logs(action);
CREATE INDEX IF NOT EXISTS idx_audit_created ON audit_logs(created_at);
CREATE INDEX IF NOT EXISTS idx_audit_correlation ON audit_logs(correlation_id);

-- Blockchain Transactions table
CREATE TABLE IF NOT EXISTS blockchain_transactions (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  tx_hash VARCHAR(66) NOT NULL UNIQUE,
  tx_type VARCHAR(50) NOT NULL,
  related_entity_type VARCHAR(50) NOT NULL,
  related_entity_id UUID NOT NULL,
  from_address VARCHAR(42) NOT NULL,
  to_address VARCHAR(42),
  status VARCHAR(20) NOT NULL DEFAULT 'PENDING',
  block_number BIGINT,
  gas_used BIGINT,
  error_message TEXT,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  confirmed_at TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_bctx_hash ON blockchain_transactions(tx_hash);
CREATE INDEX IF NOT EXISTS idx_bctx_type ON blockchain_transactions(tx_type);
CREATE INDEX IF NOT EXISTS idx_bctx_status ON blockchain_transactions(status);
CREATE INDEX IF NOT EXISTS idx_bctx_entity ON blockchain_transactions(related_entity_id);
CREATE INDEX IF NOT EXISTS idx_bctx_created ON blockchain_transactions(created_at);

-- =============================================
-- MIGRATION 2: Users, Wallets, Events, Logs
-- =============================================

-- Users table for email/password authentication
CREATE TABLE IF NOT EXISTS users (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  email VARCHAR(255) NOT NULL UNIQUE,
  password_hash VARCHAR(255) NOT NULL,
  name VARCHAR(255) NOT NULL,
  role VARCHAR(20) NOT NULL CHECK (role IN ('ADMIN', 'DEPARTMENT', 'CITIZEN')),
  department_id UUID REFERENCES departments(id) ON DELETE SET NULL,
  wallet_address VARCHAR(42),
  wallet_encrypted_key TEXT,
  phone VARCHAR(20),
  is_active BOOLEAN NOT NULL DEFAULT true,
  last_login_at TIMESTAMP,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_user_email ON users(email);
CREATE INDEX IF NOT EXISTS idx_user_role ON users(role);
CREATE INDEX IF NOT EXISTS idx_user_department ON users(department_id);
CREATE INDEX IF NOT EXISTS idx_user_active ON users(is_active);

-- Wallets table for storing encrypted private keys
CREATE TABLE IF NOT EXISTS wallets (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  address VARCHAR(42) NOT NULL UNIQUE,
  encrypted_private_key TEXT NOT NULL,
  owner_type VARCHAR(20) NOT NULL CHECK (owner_type IN ('USER', 'DEPARTMENT')),
  owner_id UUID NOT NULL,
  is_active BOOLEAN NOT NULL DEFAULT true,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_wallet_address ON wallets(address);
CREATE INDEX IF NOT EXISTS idx_wallet_owner ON wallets(owner_type, owner_id);

-- Blockchain events table
CREATE TABLE IF NOT EXISTS blockchain_events (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  tx_hash VARCHAR(66) NOT NULL,
  event_name VARCHAR(100) NOT NULL,
  contract_address VARCHAR(42) NOT NULL,
  block_number BIGINT NOT NULL,
  log_index INTEGER NOT NULL,
  args JSONB NOT NULL,
  decoded_args JSONB,
  related_entity_type VARCHAR(50),
  related_entity_id UUID,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  UNIQUE(tx_hash, log_index)
);
CREATE INDEX IF NOT EXISTS idx_event_tx ON blockchain_events(tx_hash);
CREATE INDEX IF NOT EXISTS idx_event_name ON blockchain_events(event_name);
CREATE INDEX IF NOT EXISTS idx_event_contract ON blockchain_events(contract_address);
CREATE INDEX IF NOT EXISTS idx_event_block ON blockchain_events(block_number);
CREATE INDEX IF NOT EXISTS idx_event_created ON blockchain_events(created_at);
CREATE INDEX IF NOT EXISTS idx_event_entity ON blockchain_events(related_entity_type, related_entity_id);

-- Application logs table
CREATE TABLE IF NOT EXISTS application_logs (
  id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
  level VARCHAR(10) NOT NULL CHECK (level IN ('DEBUG', 'INFO', 'WARN', 'ERROR')),
  module VARCHAR(100) NOT NULL,
  message TEXT NOT NULL,
  context JSONB,
  stack_trace TEXT,
  user_id UUID,
  correlation_id VARCHAR(100),
  ip_address VARCHAR(45),
  user_agent TEXT,
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_applog_level ON application_logs(level);
CREATE INDEX IF NOT EXISTS idx_applog_module ON application_logs(module);
CREATE INDEX IF NOT EXISTS idx_applog_user ON application_logs(user_id);
CREATE INDEX IF NOT EXISTS idx_applog_correlation ON application_logs(correlation_id);
CREATE INDEX IF NOT EXISTS idx_applog_created ON application_logs(created_at);
