import {
  quoteIdentifier,
  quoteTable,
} from '#/views/_core/database-manager/utils/sql-identifier';

export interface IndexDefinition {
  name: string;
  type: string;
  columns: string[];
  unique: boolean;
}

function normalizeDbType(dbType: string): string {
  const db = (dbType || 'postgresql').toLowerCase();
  if (db === 'sql server' || db === 'mssql') {
    return 'sqlserver';
  }
  return db;
}

/** 将后端返回的 index_type 规范化为前端枚举值 */
export function normalizeIndexType(
  indexType: string | undefined,
  dbType: string,
): string {
  const db = normalizeDbType(dbType);
  const raw = (indexType || '').toLowerCase().replaceAll(/\s+/g, '_');

  if (db === 'postgresql') {
    if (['btree', 'hash', 'gin', 'gist', 'brin'].includes(raw)) {
      return raw;
    }
    return 'btree';
  }
  if (db === 'mysql') {
    if (raw === 'hash') {
      return 'hash';
    }
    return 'btree';
  }
  if (db === 'sqlserver') {
    if (raw.includes('clustered') && !raw.includes('non')) {
      return 'clustered';
    }
    if (raw === 'hash') {
      return 'hash';
    }
    return 'nonclustered';
  }
  if (db === 'oracle') {
    if (raw.includes('bitmap')) {
      return 'bitmap';
    }
    return 'normal';
  }
  return 'btree';
}

function quoteColumnList(columns: string[], dbType: string): string {
  return columns
    .map((column) => quoteIdentifier(column, dbType))
    .join(', ');
}

function buildSqlServerIndexTypeClause(indexType: string): string {
  const type = indexType.toLowerCase();
  if (type === 'clustered') {
    return 'CLUSTERED ';
  }
  if (type === 'hash') {
    return 'NONCLUSTERED ';
  }
  return 'NONCLUSTERED ';
}

function buildOracleIndexTypeClause(indexType: string): string {
  if (indexType.toLowerCase() === 'bitmap') {
    return 'BITMAP ';
  }
  return '';
}

export function buildCreateIndexSql(
  index: IndexDefinition,
  tableRef: string,
  dbType: string,
  _schema?: string,
): string {
  const db = normalizeDbType(dbType);
  const indexName = quoteIdentifier(index.name, db);
  const indexColumns = quoteColumnList(index.columns, db);
  const uniquePrefix = index.unique ? 'UNIQUE ' : '';

  switch (db) {
    case 'mysql': {
      const indexKeyword = index.unique ? 'UNIQUE INDEX' : 'INDEX';
      return `CREATE ${indexKeyword} ${indexName} ON ${tableRef} (${indexColumns});`;
    }
    case 'sqlserver': {
      const typeClause = buildSqlServerIndexTypeClause(index.type);
      return `CREATE ${uniquePrefix}${typeClause}INDEX ${indexName} ON ${tableRef} (${indexColumns});`;
    }
    case 'oracle': {
      const typeClause = buildOracleIndexTypeClause(index.type);
      return `CREATE ${uniquePrefix}${typeClause}INDEX ${indexName} ON ${tableRef} (${indexColumns});`;
    }
    case 'postgresql':
    default: {
      const method = (index.type || 'btree').toUpperCase();
      const indexKeyword = index.unique ? 'UNIQUE INDEX' : 'INDEX';
      return `CREATE ${indexKeyword} ${indexName} ON ${tableRef} USING ${method} (${indexColumns});`;
    }
  }
}

export function buildDropIndexSql(
  index: IndexDefinition,
  tableRef: string,
  dbType: string,
  schema?: string,
): string {
  const db = normalizeDbType(dbType);
  const indexName = quoteIdentifier(index.name, db);

  switch (db) {
    case 'mysql': {
      return `DROP INDEX ${indexName} ON ${tableRef};`;
    }
    case 'sqlserver': {
      return `DROP INDEX ${indexName} ON ${tableRef};`;
    }
    case 'oracle': {
      if (schema) {
        return `DROP INDEX ${quoteIdentifier(schema, db)}.${indexName};`;
      }
      return `DROP INDEX ${indexName};`;
    }
    case 'postgresql':
    default: {
      if (schema) {
        return `DROP INDEX IF EXISTS ${quoteIdentifier(schema, db)}.${indexName};`;
      }
      return `DROP INDEX IF EXISTS ${indexName};`;
    }
  }
}

function normalizeIndexForCompare(index: IndexDefinition): IndexDefinition {
  return {
    name: index.name.trim(),
    type: (index.type || 'btree').toLowerCase(),
    columns: [...index.columns],
    unique: index.unique,
  };
}

export function indexEquals(
  left: IndexDefinition,
  right: IndexDefinition,
): boolean {
  return (
    JSON.stringify(normalizeIndexForCompare(left)) ===
    JSON.stringify(normalizeIndexForCompare(right))
  );
}

export function buildIndexAlterSql(
  originalIndexes: IndexDefinition[],
  currentIndexes: IndexDefinition[],
  tableRef: string,
  dbType: string,
  schema?: string,
): string[] {
  const statements: string[] = [];
  const originalMap = new Map(
    originalIndexes.map((item) => [item.name, item]),
  );
  const currentMap = new Map(currentIndexes.map((item) => [item.name, item]));

  for (const original of originalIndexes) {
    const current = currentMap.get(original.name);
    if (!current) {
      statements.push(buildDropIndexSql(original, tableRef, dbType, schema));
      continue;
    }
    if (!indexEquals(original, current)) {
      statements.push(buildDropIndexSql(original, tableRef, dbType, schema));
      statements.push(buildCreateIndexSql(current, tableRef, dbType, schema));
    }
  }

  for (const current of currentIndexes) {
    if (!originalMap.has(current.name)) {
      statements.push(buildCreateIndexSql(current, tableRef, dbType, schema));
    }
  }

  return statements;
}

/** 解析 API 索引数据为编辑器格式 */
export function mapIndexFromApi(
  idx: {
    index_name: string;
    index_type?: string;
    columns?: string;
    is_unique?: boolean;
  },
  dbType: string,
): IndexDefinition {
  return {
    name: idx.index_name,
    type: normalizeIndexType(idx.index_type, dbType),
    columns: idx.columns?.split(', ').filter(Boolean) || [],
    unique: Boolean(idx.is_unique),
  };
}
