import { MigrationInterface, QueryRunner } from 'typeorm';

/**
 * 多租户迁移脚本
 *
 * 此迁移将为系统添加多租户支持:
 * 1. 创建 tenants 表
 * 2. 为所有业务表添加 tenant_id 列
 * 3. 创建默认租户并回填现有数据
 * 4. 添加索引优化查询性能
 */
export class AddMultiTenancy1737817200000 implements MigrationInterface {
  name = 'AddMultiTenancy1737817200000';

  // 默认租户 ID (用于迁移现有数据)
  private readonly DEFAULT_TENANT_ID = '00000000-0000-0000-0000-000000000001';

  public async up(queryRunner: QueryRunner): Promise<void> {
    // ========== 1. 创建 tenants 表 ==========
    await queryRunner.query(`
      CREATE TABLE IF NOT EXISTS tenants (
        id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
        name VARCHAR(100) NOT NULL UNIQUE,
        slug VARCHAR(50) NOT NULL UNIQUE,
        status VARCHAR(20) NOT NULL DEFAULT 'ACTIVE',
        plan VARCHAR(30) NOT NULL DEFAULT 'STANDARD',
        max_users INT NOT NULL DEFAULT 100,
        max_conversations_per_month INT NOT NULL DEFAULT 10000,
        max_storage_mb INT NOT NULL DEFAULT 5120,
        current_user_count INT NOT NULL DEFAULT 0,
        current_conversation_count INT NOT NULL DEFAULT 0,
        current_storage_bytes BIGINT NOT NULL DEFAULT 0,
        config JSONB NOT NULL DEFAULT '{}',
        billing_email VARCHAR(255),
        billing_name VARCHAR(100),
        billing_phone VARCHAR(20),
        created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
        updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
        suspended_at TIMESTAMPTZ
      );
    `);

    // 创建 tenants 表索引
    await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_tenants_slug ON tenants(slug);`);
    await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_tenants_status ON tenants(status);`);

    // 插入默认租户
    await queryRunner.query(`
      INSERT INTO tenants (id, name, slug, status, plan)
      VALUES ('${this.DEFAULT_TENANT_ID}', 'Default Tenant', 'default', 'ACTIVE', 'ENTERPRISE')
      ON CONFLICT (id) DO NOTHING;
    `);

    // ========== 2. 为 users 表添加 tenant_id ==========
    await queryRunner.query(`ALTER TABLE users ADD COLUMN IF NOT EXISTS tenant_id UUID;`);
    await queryRunner.query(`UPDATE users SET tenant_id = '${this.DEFAULT_TENANT_ID}' WHERE tenant_id IS NULL;`);
    await queryRunner.query(`ALTER TABLE users ALTER COLUMN tenant_id SET NOT NULL;`);
    await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_users_tenant ON users(tenant_id);`);
    await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_users_tenant_phone ON users(tenant_id, phone) WHERE phone IS NOT NULL;`);
    await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_users_tenant_fingerprint ON users(tenant_id, fingerprint) WHERE fingerprint IS NOT NULL;`);

    // ========== 3. 为 verification_codes 表添加 tenant_id ==========
    await queryRunner.query(`ALTER TABLE verification_codes ADD COLUMN IF NOT EXISTS tenant_id UUID;`);
    await queryRunner.query(`UPDATE verification_codes SET tenant_id = '${this.DEFAULT_TENANT_ID}' WHERE tenant_id IS NULL;`);
    await queryRunner.query(`ALTER TABLE verification_codes ALTER COLUMN tenant_id SET NOT NULL;`);
    await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_verification_codes_tenant ON verification_codes(tenant_id);`);
    await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_verification_codes_tenant_phone ON verification_codes(tenant_id, phone);`);

    // ========== 4. 为 conversations 表添加 tenant_id ==========
    await queryRunner.query(`ALTER TABLE conversations ADD COLUMN IF NOT EXISTS tenant_id UUID;`);
    await queryRunner.query(`UPDATE conversations SET tenant_id = '${this.DEFAULT_TENANT_ID}' WHERE tenant_id IS NULL;`);
    await queryRunner.query(`ALTER TABLE conversations ALTER COLUMN tenant_id SET NOT NULL;`);
    await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_conversations_tenant ON conversations(tenant_id);`);
    await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_conversations_tenant_user ON conversations(tenant_id, user_id);`);
    await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_conversations_tenant_status ON conversations(tenant_id, status);`);

    // ========== 5. 为 messages 表添加 tenant_id ==========
    await queryRunner.query(`ALTER TABLE messages ADD COLUMN IF NOT EXISTS tenant_id UUID;`);
    await queryRunner.query(`UPDATE messages SET tenant_id = '${this.DEFAULT_TENANT_ID}' WHERE tenant_id IS NULL;`);
    await queryRunner.query(`ALTER TABLE messages ALTER COLUMN tenant_id SET NOT NULL;`);
    await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_messages_tenant ON messages(tenant_id);`);

    // ========== 6. 为 token_usages 表添加 tenant_id ==========
    await queryRunner.query(`ALTER TABLE token_usages ADD COLUMN IF NOT EXISTS tenant_id UUID;`);
    await queryRunner.query(`UPDATE token_usages SET tenant_id = '${this.DEFAULT_TENANT_ID}' WHERE tenant_id IS NULL;`);
    await queryRunner.query(`ALTER TABLE token_usages ALTER COLUMN tenant_id SET NOT NULL;`);
    await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_token_usages_tenant ON token_usages(tenant_id);`);

    // ========== 7. 为 files 表添加 tenant_id ==========
    await queryRunner.query(`ALTER TABLE files ADD COLUMN IF NOT EXISTS tenant_id UUID;`);
    await queryRunner.query(`UPDATE files SET tenant_id = '${this.DEFAULT_TENANT_ID}' WHERE tenant_id IS NULL;`);
    await queryRunner.query(`ALTER TABLE files ALTER COLUMN tenant_id SET NOT NULL;`);
    await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_files_tenant ON files(tenant_id);`);
    await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_files_tenant_user ON files(tenant_id, user_id);`);

    // ========== 8. 为 knowledge_articles 表添加 tenant_id ==========
    await queryRunner.query(`ALTER TABLE knowledge_articles ADD COLUMN IF NOT EXISTS tenant_id UUID;`);
    await queryRunner.query(`UPDATE knowledge_articles SET tenant_id = '${this.DEFAULT_TENANT_ID}' WHERE tenant_id IS NULL;`);
    await queryRunner.query(`ALTER TABLE knowledge_articles ALTER COLUMN tenant_id SET NOT NULL;`);
    await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_knowledge_articles_tenant ON knowledge_articles(tenant_id);`);

    // ========== 9. 为 knowledge_chunks 表添加 tenant_id ==========
    await queryRunner.query(`ALTER TABLE knowledge_chunks ADD COLUMN IF NOT EXISTS tenant_id UUID;`);
    await queryRunner.query(`UPDATE knowledge_chunks SET tenant_id = '${this.DEFAULT_TENANT_ID}' WHERE tenant_id IS NULL;`);
    await queryRunner.query(`ALTER TABLE knowledge_chunks ALTER COLUMN tenant_id SET NOT NULL;`);
    await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_knowledge_chunks_tenant ON knowledge_chunks(tenant_id);`);

    // ========== 10. 为 user_memories 表添加 tenant_id ==========
    await queryRunner.query(`ALTER TABLE user_memories ADD COLUMN IF NOT EXISTS tenant_id UUID;`);
    await queryRunner.query(`UPDATE user_memories SET tenant_id = '${this.DEFAULT_TENANT_ID}' WHERE tenant_id IS NULL;`);
    await queryRunner.query(`ALTER TABLE user_memories ALTER COLUMN tenant_id SET NOT NULL;`);
    await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_user_memories_tenant ON user_memories(tenant_id);`);

    // ========== 11. 为 system_experiences 表添加 tenant_id ==========
    await queryRunner.query(`ALTER TABLE system_experiences ADD COLUMN IF NOT EXISTS tenant_id UUID;`);
    await queryRunner.query(`UPDATE system_experiences SET tenant_id = '${this.DEFAULT_TENANT_ID}' WHERE tenant_id IS NULL;`);
    await queryRunner.query(`ALTER TABLE system_experiences ALTER COLUMN tenant_id SET NOT NULL;`);
    await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_system_experiences_tenant ON system_experiences(tenant_id);`);

    // ========== 12. 为 orders 表添加 tenant_id ==========
    await queryRunner.query(`ALTER TABLE orders ADD COLUMN IF NOT EXISTS tenant_id UUID;`);
    await queryRunner.query(`UPDATE orders SET tenant_id = '${this.DEFAULT_TENANT_ID}' WHERE tenant_id IS NULL;`);
    await queryRunner.query(`ALTER TABLE orders ALTER COLUMN tenant_id SET NOT NULL;`);
    await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_orders_tenant ON orders(tenant_id);`);
    await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_orders_tenant_user ON orders(tenant_id, user_id);`);

    // ========== 13. 为 payments 表添加 tenant_id ==========
    await queryRunner.query(`ALTER TABLE payments ADD COLUMN IF NOT EXISTS tenant_id UUID;`);
    await queryRunner.query(`UPDATE payments SET tenant_id = '${this.DEFAULT_TENANT_ID}' WHERE tenant_id IS NULL;`);
    await queryRunner.query(`ALTER TABLE payments ALTER COLUMN tenant_id SET NOT NULL;`);
    await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_payments_tenant ON payments(tenant_id);`);

    // ========== 14. 为 admins 表添加 tenant_id 和 is_super_admin ==========
    await queryRunner.query(`ALTER TABLE admins ADD COLUMN IF NOT EXISTS tenant_id UUID;`);
    await queryRunner.query(`ALTER TABLE admins ADD COLUMN IF NOT EXISTS is_super_admin BOOLEAN DEFAULT false;`);
    // 将现有管理员设置为默认租户的管理员
    await queryRunner.query(`UPDATE admins SET tenant_id = '${this.DEFAULT_TENANT_ID}' WHERE tenant_id IS NULL AND is_super_admin = false;`);
    await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_admins_tenant ON admins(tenant_id);`);
    await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_admins_username_tenant ON admins(tenant_id, username);`);

    // ========== 15. 为 daily_statistics 表添加 tenant_id ==========
    await queryRunner.query(`ALTER TABLE daily_statistics ADD COLUMN IF NOT EXISTS tenant_id UUID;`);
    await queryRunner.query(`UPDATE daily_statistics SET tenant_id = '${this.DEFAULT_TENANT_ID}' WHERE tenant_id IS NULL;`);
    await queryRunner.query(`ALTER TABLE daily_statistics ALTER COLUMN tenant_id SET NOT NULL;`);
    await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_daily_statistics_tenant ON daily_statistics(tenant_id);`);
    // 更新唯一约束
    await queryRunner.query(`ALTER TABLE daily_statistics DROP CONSTRAINT IF EXISTS daily_statistics_stat_date_dimension_dimension_value_key;`);
    await queryRunner.query(`ALTER TABLE daily_statistics ADD CONSTRAINT daily_statistics_tenant_date_dim_unique UNIQUE(tenant_id, stat_date, dimension, dimension_value);`);

    // ========== 16. 为 monthly_financial_reports 表添加 tenant_id ==========
    await queryRunner.query(`ALTER TABLE monthly_financial_reports ADD COLUMN IF NOT EXISTS tenant_id UUID;`);
    await queryRunner.query(`UPDATE monthly_financial_reports SET tenant_id = '${this.DEFAULT_TENANT_ID}' WHERE tenant_id IS NULL;`);
    await queryRunner.query(`ALTER TABLE monthly_financial_reports ALTER COLUMN tenant_id SET NOT NULL;`);
    await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_monthly_financial_reports_tenant ON monthly_financial_reports(tenant_id);`);
    // 更新唯一约束 (移除原有的 report_month unique，改为 tenant_id + report_month)
    await queryRunner.query(`ALTER TABLE monthly_financial_reports DROP CONSTRAINT IF EXISTS monthly_financial_reports_report_month_key;`);
    await queryRunner.query(`ALTER TABLE monthly_financial_reports ADD CONSTRAINT monthly_financial_reports_tenant_month_unique UNIQUE(tenant_id, report_month);`);

    // ========== 17. 为 audit_logs 表添加 tenant_id ==========
    await queryRunner.query(`ALTER TABLE audit_logs ADD COLUMN IF NOT EXISTS tenant_id UUID;`);
    await queryRunner.query(`UPDATE audit_logs SET tenant_id = '${this.DEFAULT_TENANT_ID}' WHERE tenant_id IS NULL;`);
    await queryRunner.query(`ALTER TABLE audit_logs ALTER COLUMN tenant_id SET NOT NULL;`);
    await queryRunner.query(`CREATE INDEX IF NOT EXISTS idx_audit_logs_tenant ON audit_logs(tenant_id);`);
  }

  public async down(queryRunner: QueryRunner): Promise<void> {
    // 回滚: 删除所有 tenant_id 列和相关索引
    // 注意: 这是破坏性操作，会丢失租户隔离

    // audit_logs
    await queryRunner.query(`DROP INDEX IF EXISTS idx_audit_logs_tenant;`);
    await queryRunner.query(`ALTER TABLE audit_logs DROP COLUMN IF EXISTS tenant_id;`);

    // monthly_financial_reports
    await queryRunner.query(`ALTER TABLE monthly_financial_reports DROP CONSTRAINT IF EXISTS monthly_financial_reports_tenant_month_unique;`);
    await queryRunner.query(`ALTER TABLE monthly_financial_reports ADD CONSTRAINT monthly_financial_reports_report_month_key UNIQUE(report_month);`);
    await queryRunner.query(`DROP INDEX IF EXISTS idx_monthly_financial_reports_tenant;`);
    await queryRunner.query(`ALTER TABLE monthly_financial_reports DROP COLUMN IF EXISTS tenant_id;`);

    // daily_statistics
    await queryRunner.query(`ALTER TABLE daily_statistics DROP CONSTRAINT IF EXISTS daily_statistics_tenant_date_dim_unique;`);
    await queryRunner.query(`ALTER TABLE daily_statistics ADD CONSTRAINT daily_statistics_stat_date_dimension_dimension_value_key UNIQUE(stat_date, dimension, dimension_value);`);
    await queryRunner.query(`DROP INDEX IF EXISTS idx_daily_statistics_tenant;`);
    await queryRunner.query(`ALTER TABLE daily_statistics DROP COLUMN IF EXISTS tenant_id;`);

    // admins
    await queryRunner.query(`DROP INDEX IF EXISTS idx_admins_username_tenant;`);
    await queryRunner.query(`DROP INDEX IF EXISTS idx_admins_tenant;`);
    await queryRunner.query(`ALTER TABLE admins DROP COLUMN IF EXISTS is_super_admin;`);
    await queryRunner.query(`ALTER TABLE admins DROP COLUMN IF EXISTS tenant_id;`);

    // payments
    await queryRunner.query(`DROP INDEX IF EXISTS idx_payments_tenant;`);
    await queryRunner.query(`ALTER TABLE payments DROP COLUMN IF EXISTS tenant_id;`);

    // orders
    await queryRunner.query(`DROP INDEX IF EXISTS idx_orders_tenant_user;`);
    await queryRunner.query(`DROP INDEX IF EXISTS idx_orders_tenant;`);
    await queryRunner.query(`ALTER TABLE orders DROP COLUMN IF EXISTS tenant_id;`);

    // system_experiences
    await queryRunner.query(`DROP INDEX IF EXISTS idx_system_experiences_tenant;`);
    await queryRunner.query(`ALTER TABLE system_experiences DROP COLUMN IF EXISTS tenant_id;`);

    // user_memories
    await queryRunner.query(`DROP INDEX IF EXISTS idx_user_memories_tenant;`);
    await queryRunner.query(`ALTER TABLE user_memories DROP COLUMN IF EXISTS tenant_id;`);

    // knowledge_chunks
    await queryRunner.query(`DROP INDEX IF EXISTS idx_knowledge_chunks_tenant;`);
    await queryRunner.query(`ALTER TABLE knowledge_chunks DROP COLUMN IF EXISTS tenant_id;`);

    // knowledge_articles
    await queryRunner.query(`DROP INDEX IF EXISTS idx_knowledge_articles_tenant;`);
    await queryRunner.query(`ALTER TABLE knowledge_articles DROP COLUMN IF EXISTS tenant_id;`);

    // files
    await queryRunner.query(`DROP INDEX IF EXISTS idx_files_tenant_user;`);
    await queryRunner.query(`DROP INDEX IF EXISTS idx_files_tenant;`);
    await queryRunner.query(`ALTER TABLE files DROP COLUMN IF EXISTS tenant_id;`);

    // token_usages
    await queryRunner.query(`DROP INDEX IF EXISTS idx_token_usages_tenant;`);
    await queryRunner.query(`ALTER TABLE token_usages DROP COLUMN IF EXISTS tenant_id;`);

    // messages
    await queryRunner.query(`DROP INDEX IF EXISTS idx_messages_tenant;`);
    await queryRunner.query(`ALTER TABLE messages DROP COLUMN IF EXISTS tenant_id;`);

    // conversations
    await queryRunner.query(`DROP INDEX IF EXISTS idx_conversations_tenant_status;`);
    await queryRunner.query(`DROP INDEX IF EXISTS idx_conversations_tenant_user;`);
    await queryRunner.query(`DROP INDEX IF EXISTS idx_conversations_tenant;`);
    await queryRunner.query(`ALTER TABLE conversations DROP COLUMN IF EXISTS tenant_id;`);

    // verification_codes
    await queryRunner.query(`DROP INDEX IF EXISTS idx_verification_codes_tenant_phone;`);
    await queryRunner.query(`DROP INDEX IF EXISTS idx_verification_codes_tenant;`);
    await queryRunner.query(`ALTER TABLE verification_codes DROP COLUMN IF EXISTS tenant_id;`);

    // users
    await queryRunner.query(`DROP INDEX IF EXISTS idx_users_tenant_fingerprint;`);
    await queryRunner.query(`DROP INDEX IF EXISTS idx_users_tenant_phone;`);
    await queryRunner.query(`DROP INDEX IF EXISTS idx_users_tenant;`);
    await queryRunner.query(`ALTER TABLE users DROP COLUMN IF EXISTS tenant_id;`);

    // tenants 表
    await queryRunner.query(`DROP INDEX IF EXISTS idx_tenants_status;`);
    await queryRunner.query(`DROP INDEX IF EXISTS idx_tenants_slug;`);
    await queryRunner.query(`DROP TABLE IF EXISTS tenants;`);
  }
}
