use sea_orm_migration::prelude::*;

/// 修复 settings 表唯一索引：原索引使用 scope_id 列，当 scope_id 为 NULL 时
/// PostgreSQL B-tree 不认为两行重复（NULL != NULL），导致可插入重复数据。
/// 修复方案：使用 COALESCE(scope_id, '00000000-0000-0000-0000-000000000000')
/// 将 NULL 转为固定 UUID，使索引能正确约束 NULL scope_id 的行。
#[derive(DeriveMigrationName)]
pub struct Migration;

#[async_trait::async_trait]
impl MigrationTrait for Migration {
    async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
        // 1. 删除旧索引
        manager
            .get_connection()
            .execute(sea_orm::Statement::from_string(
                sea_orm::DatabaseBackend::Postgres,
                "DROP INDEX IF EXISTS idx_settings_scope_key".to_string(),
            ))
            .await
            .map_err(|e| DbErr::Custom(e.to_string()))?;

        // 2. 先清理可能已存在的重复数据（保留每组最新的一条）
        manager.get_connection().execute(sea_orm::Statement::from_string(
            sea_orm::DatabaseBackend::Postgres,
            r#"
            DELETE FROM settings a USING settings b
            WHERE a.id < b.id
              AND a.tenant_id = b.tenant_id
              AND a.scope = b.scope
              AND a.setting_key = b.setting_key
              AND a.deleted_at IS NULL
              AND b.deleted_at IS NULL
              AND COALESCE(a.scope_id, '00000000-0000-0000-0000-000000000000') = COALESCE(b.scope_id, '00000000-0000-0000-0000-000000000000')
            "#.to_string(),
        )).await.map_err(|e| DbErr::Custom(e.to_string()))?;

        // 3. 创建新索引，使用 COALESCE 处理 NULL scope_id
        manager.get_connection().execute(sea_orm::Statement::from_string(
            sea_orm::DatabaseBackend::Postgres,
            "CREATE UNIQUE INDEX idx_settings_scope_key ON settings (tenant_id, scope, COALESCE(scope_id, '00000000-0000-0000-0000-000000000000'), setting_key) WHERE deleted_at IS NULL".to_string(),
        )).await.map_err(|e| DbErr::Custom(e.to_string()))?;

        Ok(())
    }

    async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
        // 回滚：删除新索引，恢复旧索引
        manager
            .get_connection()
            .execute(sea_orm::Statement::from_string(
                sea_orm::DatabaseBackend::Postgres,
                "DROP INDEX IF EXISTS idx_settings_scope_key".to_string(),
            ))
            .await
            .map_err(|e| DbErr::Custom(e.to_string()))?;

        manager.get_connection().execute(sea_orm::Statement::from_string(
            sea_orm::DatabaseBackend::Postgres,
            "CREATE UNIQUE INDEX idx_settings_scope_key ON settings (tenant_id, scope, scope_id, setting_key) WHERE deleted_at IS NULL".to_string(),
        )).await.map_err(|e| DbErr::Custom(e.to_string()))?;

        Ok(())
    }
}
