﻿import { useState, useCallback, useMemo, useEffect } from 'react'
import classNames from 'classnames'
import { createPortal } from 'react-dom'
import { Button, Dialog, Notification, toast, Checkbox } from '@/components/ui'
import { useDialogContext } from '@/components/ui/Dialog/Dialog'
import {
  FaPlus,
  FaTrash,
  FaArrowUp,
  FaArrowDown,
  FaTable,
  FaCloudUploadAlt,
  FaCheck,
  FaLink,
  FaEdit,
  FaTimes,
  FaArrowRight,
  FaChevronDown,
  FaChevronRight,
  FaKey,
} from 'react-icons/fa'
import { sqlObjectManagerService } from '@/services/sql-query-manager.service'
import { getMenus } from '@/services/menu.service'
import { useLocalization } from '@/utils/hooks/useLocalization'
import { CascadeBehavior, SqlTableRelation, RelationshipType } from '@/proxy/developerKit/models'
import navigationIcon from '@/proxy/menus/navigation-icon.config'
import { MenuItem } from '@/proxy/menus/menu'
import {
  MenuTreeNode,
  buildMenuTree,
  filterNonLinkNodes,
} from '@/views/admin/listForm/wizard/WizardStep1'
import { MenuAddDialog } from '../shared/MenuAddDialog'

// ─── Types ────────────────────────────────────────────────────────────────────

type SqlDataType =
  | 'nvarchar'
  | 'nvarchar(MAX)'
  | 'int'
  | 'bigint'
  | 'decimal'
  | 'float'
  | 'bit'
  | 'datetime2'
  | 'date'
  | 'uniqueidentifier'
  | 'money'

interface ColumnDefinition {
  id: string
  columnName: string
  dataType: SqlDataType
  maxLength: string
  isNullable: boolean
  defaultValue: string
  description: string
}

interface TableSettings {
  menuValue: string
  menuPrefix: string
  entityName: string
  tableName: string
}

interface TableDesignerDialogProps {
  isOpen: boolean
  onClose: () => void
  dataSource: string | null
  onDeployed?: () => void
  initialTableData?: { schemaName: string; tableName: string } | null
}

type IndexType = 'PrimaryKey' | 'UniqueKey' | 'Index'

interface IndexColumnEntry {
  columnName: string
  order: 'ASC' | 'DESC'
}

interface TableIndex {
  id: string
  indexName: string
  indexType: IndexType
  isClustered: boolean
  columns: IndexColumnEntry[]
  description: string
}

// ─── Constants ────────────────────────────────────────────────────────────────

const DATA_TYPES: { value: SqlDataType; label: string }[] = [
  { value: 'nvarchar', label: 'String (nvarchar)' },
  { value: 'nvarchar(MAX)', label: 'Text (nvarchar MAX)' },
  { value: 'int', label: 'Int (int)' },
  { value: 'bigint', label: 'Long (bigint)' },
  { value: 'decimal', label: 'Decimal (decimal 18,4)' },
  { value: 'float', label: 'Float (float)' },
  { value: 'bit', label: 'Bool (bit)' },
  { value: 'datetime2', label: 'DateTime (datetime2)' },
  { value: 'date', label: 'Date (date)' },
  { value: 'uniqueidentifier', label: 'Guid (uniqueidentifier)' },
  { value: 'money', label: 'Money (money)' },
]

const FULL_AUDIT_COLUMNS: ColumnDefinition[] = [
  {
    id: '__Id',
    columnName: 'Id',
    dataType: 'uniqueidentifier',
    maxLength: '',
    isNullable: false,
    defaultValue: 'NEWID()',
    description: 'Primary key',
  },
  {
    id: '__CreationTime',
    columnName: 'CreationTime',
    dataType: 'datetime2',
    maxLength: '',
    isNullable: false,
    defaultValue: 'GETUTCDATE()',
    description: 'Record creation time',
  },
  {
    id: '__CreatorId',
    columnName: 'CreatorId',
    dataType: 'uniqueidentifier',
    maxLength: '',
    isNullable: true,
    defaultValue: '',
    description: 'Creator user ID',
  },
  {
    id: '__LastModificationTime',
    columnName: 'LastModificationTime',
    dataType: 'datetime2',
    maxLength: '',
    isNullable: true,
    defaultValue: '',
    description: 'Last modification time',
  },
  {
    id: '__LastModifierId',
    columnName: 'LastModifierId',
    dataType: 'uniqueidentifier',
    maxLength: '',
    isNullable: true,
    defaultValue: '',
    description: 'Last modifier user ID',
  },
  {
    id: '__IsDeleted',
    columnName: 'IsDeleted',
    dataType: 'bit',
    maxLength: '',
    isNullable: false,
    defaultValue: '0',
    description: 'Soft delete flag',
  },
  {
    id: '__DeletionTime',
    columnName: 'DeletionTime',
    dataType: 'datetime2',
    maxLength: '',
    isNullable: true,
    defaultValue: '',
    description: 'Deletion time',
  },
  {
    id: '__DeleterId',
    columnName: 'DeleterId',
    dataType: 'uniqueidentifier',
    maxLength: '',
    isNullable: true,
    defaultValue: '',
    description: 'Deleter user ID',
  },
]

const REL_TYPES: { value: RelationshipType; label: string; desc: string }[] = [
  { value: 'OneToMany', label: '1 → N', desc: 'Bire-çok' },
  { value: 'OneToOne', label: '1 → 1', desc: 'Bire-bir' },
]

const CASCADE_OPTIONS: { value: CascadeBehavior; label: string }[] = [
  { value: 'NoAction', label: 'No Action' },
  { value: 'Cascade', label: 'Cascade' },
  { value: 'SetNull', label: 'Set Null' },
  { value: 'Restrict', label: 'Restrict' },
]

const EMPTY_FK: Omit<SqlTableRelation, 'id'> = {
  relationshipType: 'OneToMany',
  fkColumnName: '',
  referencedTable: '',
  referencedColumn: 'Id',
  cascadeDelete: 'NoAction',
  cascadeUpdate: 'Cascade',
  isRequired: false,
  description: '',
}

const EMPTY_INDEX: Omit<TableIndex, 'id'> = {
  indexName: '',
  indexType: 'Index',
  isClustered: false,
  columns: [],
  description: '',
}

const INDEX_TYPES: { value: IndexType; label: string; desc: string }[] = [
  { value: 'PrimaryKey', label: 'Primary Key', desc: 'App.SqlQueryManager.IndexType_PrimaryKey_Desc' },
  { value: 'UniqueKey', label: 'Unique Key', desc: 'App.SqlQueryManager.IndexType_UniqueKey_Desc' },
  { value: 'Index', label: 'Index', desc: 'App.SqlQueryManager.IndexType_Index_Desc' },
]

const TENANT_COLUMN: ColumnDefinition = {
  id: '__TenantId',
  columnName: 'TenantId',
  dataType: 'uniqueidentifier',
  maxLength: '',
  isNullable: true,
  defaultValue: '',
  description: 'Tenant ID for multi-tenancy',
}

const CREATE_TABLE_SCRIPT_STORAGE_KEY = 'sqlQueryManager.lastCreateTableScript'

// ─── T-SQL Generator ──────────────────────────────────────────────────────────

function colToSqlLine(col: ColumnDefinition, addComma = true): string {
  let typeSql: string
  switch (col.dataType) {
    case 'nvarchar':
      typeSql = `nvarchar(${col.maxLength || '100'})`
      break
    case 'nvarchar(MAX)':
      typeSql = 'nvarchar(MAX)'
      break
    case 'decimal':
      typeSql = 'decimal(18, 4)'
      break
    default:
      typeSql = col.dataType
  }
  const nullPart = col.isNullable ? 'NULL' : 'NOT NULL'
  const defaultPart = col.defaultValue ? ` DEFAULT ${col.defaultValue}` : ''
  return `        [${col.columnName}] ${typeSql} ${nullPart}${defaultPart}${addComma ? ',' : ''}`
}

function generateCreateTableSql(
  columns: ColumnDefinition[],
  settings: TableSettings,
  relationships: SqlTableRelation[],
  indexes: TableIndex[],
): string {
  const tableName = settings.tableName || 'NewTable'
  const fullTableName = `[dbo].[${tableName}]`
  const escapedFullTableName = fullTableName.replace(/'/g, "''")

  const userCols = columns.filter((c) => c.columnName.trim())
  const bodyLines = userCols.map((c) => colToSqlLine(c, false))

  // Inline PRIMARY KEY constraint inside CREATE TABLE
  const pkIndex = indexes.find((idx) => idx.indexType === 'PrimaryKey' && idx.columns.length > 0)
  const pkConstraintLines: string[] = []
  if (pkIndex) {
    const clustered = pkIndex.isClustered ? 'CLUSTERED' : 'NONCLUSTERED'
    const colsSql = pkIndex.columns.map((c) => `        [${c.columnName}] ${c.order}`).join(',\n')
    pkConstraintLines.push(
      `        CONSTRAINT [${pkIndex.indexName}] PRIMARY KEY ${clustered}`,
      `    (`,
      colsSql,
      `    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]`,
    )
  }

  // Build all column + pk lines with commas
  const allInnerLines: string[] = []
  for (let i = 0; i < bodyLines.length; i++) {
    allInnerLines.push(bodyLines[i] + ',')
  }
  if (pkConstraintLines.length > 0) {
    for (let i = 0; i < pkConstraintLines.length; i++) {
      allInnerLines.push(pkConstraintLines[i])
    }
  } else if (allInnerLines.length > 0) {
    // Remove trailing comma from last column if no PK
    allInnerLines[allInnerLines.length - 1] = allInnerLines[allInnerLines.length - 1].replace(/,$/, '')
  }

  // Non-PK index lines (UNIQUE, regular INDEX) — outside CREATE TABLE
  const extraIndexLines: string[] = []
  for (const idx of indexes) {
    if (idx.columns.length === 0 || idx.indexType === 'PrimaryKey') continue
    const clustered = idx.isClustered ? 'CLUSTERED' : 'NONCLUSTERED'
    const colsSql = idx.columns.map((c) => `[${c.columnName}] ${c.order}`).join(', ')
    extraIndexLines.push('')
    if (idx.indexType === 'UniqueKey') {
      extraIndexLines.push(`-- 🔒 Unique Key: [${idx.indexName}]`)
      extraIndexLines.push(`ALTER TABLE ${fullTableName}`)
      extraIndexLines.push(`    ADD CONSTRAINT [${idx.indexName}] UNIQUE ${clustered} (${colsSql});`)
    } else {
      extraIndexLines.push(`-- 📋 Index: [${idx.indexName}]`)
      extraIndexLines.push(
        `CREATE ${idx.isClustered ? 'CLUSTERED ' : ''}INDEX [${idx.indexName}] ON ${fullTableName} (${colsSql});`,
      )
    }
  }

  // FK constraint lines
  const fkLines: string[] = []
  for (const rel of relationships) {
    if (!rel.fkColumnName.trim() || !rel.referencedTable.trim()) continue
    const constraintName = `FK_${tableName}_${rel.fkColumnName}`
    const cascadeDelete =
      rel.cascadeDelete === 'NoAction'
        ? 'NO ACTION'
        : rel.cascadeDelete
            .replace(/([A-Z])/g, ' $1')
            .trim()
            .toUpperCase()
    const cascadeUpdate =
      rel.cascadeUpdate === 'NoAction'
        ? 'NO ACTION'
        : rel.cascadeUpdate
            .replace(/([A-Z])/g, ' $1')
            .trim()
            .toUpperCase()
    fkLines.push('')
    fkLines.push(`ALTER TABLE ${fullTableName}`)
    fkLines.push(`    ADD CONSTRAINT [${constraintName}]`)
    fkLines.push(`    FOREIGN KEY ([${rel.fkColumnName}])`)
    fkLines.push(
      `    REFERENCES [dbo].[${rel.referencedTable}] ([${rel.referencedColumn || 'Id'}])`,
    )
    fkLines.push(`    ON DELETE ${cascadeDelete}`)
    fkLines.push(`    ON UPDATE ${cascadeUpdate};`)
  }

  const lines: string[] = [
    `IF OBJECT_ID(N'${escapedFullTableName}', 'U') IS NULL`,
    `BEGIN`,
    `    CREATE TABLE ${fullTableName}`,
    `    (`,
    ...allInnerLines,
    `    ) ON [PRIMARY]`,
    `END`,
    `GO`,
    ...extraIndexLines,
    ...(fkLines.length > 0 ? ['', '/* Foreign Key Constraints */'] : []),
    ...fkLines,
  ]

  return lines.join('\n')
}

// ─── Helpers ──────────────────────────────────────────────────────────────────

/** Convert a DatabaseColumnDto (from API) to a ColumnDefinition for the grid */
function dbColToColumnDef(col: {
  columnName: string
  dataType: string
  isNullable: boolean
  maxLength?: number
}): ColumnDefinition {
  const dt = col.dataType.toLowerCase().trim()
  let dataType: SqlDataType = 'nvarchar'
  let maxLength = ''

  if (dt === 'nvarchar' || dt === 'varchar' || dt === 'char' || dt === 'nchar') {
    dataType = col.maxLength === -1 ? 'nvarchar(MAX)' : 'nvarchar'
    maxLength = col.maxLength && col.maxLength > 0 ? String(col.maxLength) : ''
  } else if (dt === 'int') {
    dataType = 'int'
  } else if (dt === 'bigint') {
    dataType = 'bigint'
  } else if (dt === 'decimal' || dt === 'numeric') {
    dataType = 'decimal'
  } else if (dt === 'float' || dt === 'real') {
    dataType = 'float'
  } else if (dt === 'bit') {
    dataType = 'bit'
  } else if (dt.startsWith('datetime') || dt === 'smalldatetime') {
    dataType = 'datetime2'
  } else if (dt === 'date') {
    dataType = 'date'
  } else if (dt === 'uniqueidentifier') {
    dataType = 'uniqueidentifier'
  } else if (dt === 'money' || dt === 'smallmoney') {
    dataType = 'money'
  }

  return {
    id: crypto.randomUUID(),
    columnName: col.columnName,
    dataType,
    maxLength,
    isNullable: col.isNullable,
    defaultValue: '',
    description: '',
  }
}

function splitByTopLevelComma(input: string): string[] {
  const parts: string[] = []
  let current = ''
  let depth = 0

  for (let i = 0; i < input.length; i++) {
    const ch = input[i]
    if (ch === '(') depth++
    if (ch === ')') depth = Math.max(0, depth - 1)

    if (ch === ',' && depth === 0) {
      if (current.trim()) parts.push(current.trim())
      current = ''
      continue
    }

    current += ch
  }

  if (current.trim()) parts.push(current.trim())
  return parts
}

function unwrapDefaultExpression(value: string): string {
  let result = value.trim()
  while (result.startsWith('(') && result.endsWith(')')) {
    result = result.slice(1, -1).trim()
  }
  return result
}

function mapSqlTypeToDesigner(dataTypeRaw: string, lengthRaw: string): {
  dataType: SqlDataType
  maxLength: string
} {
  const dt = dataTypeRaw.toLowerCase()
  const len = lengthRaw.toLowerCase()

  if (dt === 'nvarchar' || dt === 'varchar' || dt === 'char' || dt === 'nchar') {
    if (len === 'max') {
      return { dataType: 'nvarchar(MAX)', maxLength: '' }
    }
    return { dataType: 'nvarchar', maxLength: len || '100' }
  }

  if (dt === 'int') return { dataType: 'int', maxLength: '' }
  if (dt === 'bigint') return { dataType: 'bigint', maxLength: '' }
  if (dt === 'decimal' || dt === 'numeric') return { dataType: 'decimal', maxLength: '' }
  if (dt === 'float' || dt === 'real') return { dataType: 'float', maxLength: '' }
  if (dt === 'bit') return { dataType: 'bit', maxLength: '' }
  if (dt.startsWith('datetime') || dt === 'smalldatetime' || dt === 'time') {
    return { dataType: 'datetime2', maxLength: '' }
  }
  if (dt === 'date') return { dataType: 'date', maxLength: '' }
  if (dt === 'uniqueidentifier') return { dataType: 'uniqueidentifier', maxLength: '' }
  if (dt === 'money' || dt === 'smallmoney') return { dataType: 'money', maxLength: '' }

  return { dataType: 'nvarchar', maxLength: '100' }
}

function parseCreateTableColumns(script: string): ColumnDefinition[] {
  if (!script?.trim()) return []

  const createIdx = script.search(/\bCREATE\s+TABLE\b/i)
  if (createIdx < 0) return []

  const openParenIdx = script.indexOf('(', createIdx)
  if (openParenIdx < 0) return []

  let depth = 0
  let closeParenIdx = -1
  for (let i = openParenIdx; i < script.length; i++) {
    const ch = script[i]
    if (ch === '(') depth++
    if (ch === ')') {
      depth--
      if (depth === 0) {
        closeParenIdx = i
        break
      }
    }
  }

  if (closeParenIdx < 0) return []

  const body = script.slice(openParenIdx + 1, closeParenIdx)
  const defs = splitByTopLevelComma(body)
  const columns: ColumnDefinition[] = []

  for (const def of defs) {
    const trimmed = def.trim()
    if (!trimmed) continue

    if (
      /^(CONSTRAINT|PRIMARY\s+KEY|UNIQUE\s+KEY|UNIQUE|FOREIGN\s+KEY|CHECK)\b/i.test(trimmed)
    ) {
      continue
    }

    const colMatch = trimmed.match(/^\[([^\]]+)\]\s+(.+)$/i)
    if (!colMatch) continue

    const columnName = colMatch[1].trim()
    const rest = colMatch[2].trim()

    const typeMatch = rest.match(/^\[?([A-Za-z0-9_]+)\]?\s*(?:\(([^)]*)\))?/)
    if (!typeMatch) continue

    const sqlType = typeMatch[1] ?? 'nvarchar'
    const sqlLength = (typeMatch[2] ?? '').trim()
    const mapped = mapSqlTypeToDesigner(sqlType, sqlLength)

    const isNullable = !/\bNOT\s+NULL\b/i.test(rest)
    const defaultMatch = rest.match(/\bDEFAULT\b\s+(.+)$/i)
    const defaultValue = defaultMatch ? unwrapDefaultExpression(defaultMatch[1]) : ''

    columns.push({
      id: crypto.randomUUID(),
      columnName,
      dataType: mapped.dataType,
      maxLength: mapped.maxLength,
      isNullable,
      defaultValue,
      description: '',
    })
  }

  return columns
}

/** Generate ALTER TABLE diff SQL (edit mode) */
function generateAlterTableSql(
  originalCols: ColumnDefinition[],
  currentCols: ColumnDefinition[],
  tableName: string,
  relationships: SqlTableRelation[],
  originalRelationships: SqlTableRelation[],
  indexes: TableIndex[],
  originalIndexes: TableIndex[],
): string {
  const fullTableName = `[dbo].[${tableName}]`
  const lines: string[] = [`/* ── ALTER TABLE: ${fullTableName} ── */`, '']
  let hasChanges = false

  // Build id-based maps for O(1) lookup
  const origById = new Map<string, ColumnDefinition>()
  originalCols.forEach((c) => origById.set(c.id, c))

  const curById = new Map<string, ColumnDefinition>()
  currentCols.filter((c) => c.columnName.trim()).forEach((c) => curById.set(c.id, c))

  // ➕ Added columns (id exists in current but NOT in original)
  currentCols
    .filter((c) => c.columnName.trim())
    .forEach((col) => {
      if (!origById.has(col.id)) {
        hasChanges = true
        lines.push(`-- ➕ Yeni Sütun: [${col.columnName}]`)
        lines.push(`ALTER TABLE ${fullTableName}`)
        lines.push(`    ADD ${colToSqlLine(col, false).trimStart()};`)
        lines.push('')
      }
    })

  // ❌ Silinen sütunlar (id exists in original but NOT in current)
  originalCols.forEach((col) => {
    if (!curById.has(col.id)) {
      hasChanges = true
      lines.push(`-- ❌ Silinen Sütun: [${col.columnName}]`)
      lines.push(`ALTER TABLE ${fullTableName}`)
      lines.push(`    DROP COLUMN [${col.columnName}];`)
      lines.push('')
    }
  })

  // ✏️ Renamed / Modified columns (same id in both)
  currentCols
    .filter((c) => c.columnName.trim())
    .forEach((col) => {
      const orig = origById.get(col.id)
      if (!orig) return // new column, already handled above

      const nameChanged =
        orig.columnName.trim().toLowerCase() !== col.columnName.trim().toLowerCase()
      const typeChanged = orig.dataType !== col.dataType || orig.maxLength !== col.maxLength
      const nullChanged = orig.isNullable !== col.isNullable

      // Rename: use sp_rename to preserve data
      if (nameChanged) {
        hasChanges = true
        lines.push(`-- 🔄 Sütun Yeniden Adlandırma: [${orig.columnName}] → [${col.columnName}]`)
        lines.push(
          `EXEC sp_rename 'dbo.${tableName}.${orig.columnName}', '${col.columnName}', 'COLUMN';`,
        )
        lines.push('')
      }

      // Type or nullability change: ALTER COLUMN (uses new name if also renamed)
      if (typeChanged || nullChanged) {
        hasChanges = true
        const label = nameChanged
          ? `-- ✏️ Değiştirilen Sütun (yeniden adlandırıldıktan sonra): [${col.columnName}]`
          : `-- ✏️ Değiştirilen Sütun: [${col.columnName}]`
        lines.push(label)
        lines.push(`ALTER TABLE ${fullTableName}`)
        lines.push(
          `    ALTER COLUMN ${colToSqlLine({ ...col, defaultValue: '' }, false).trimStart()};`,
        )
        lines.push('')
      }
    })

  // 🔗 FK Diff: drop removed / drop+re-add modified / add new
  const fkCascadeSql = (b: CascadeBehavior) =>
    b === 'NoAction'
      ? 'NO ACTION'
      : b
          .replace(/([A-Z])/g, ' $1')
          .trim()
          .toUpperCase()

  const addFkSql = (rel: SqlTableRelation) => {
    const cname = rel.constraintName ?? `FK_${tableName}_${rel.fkColumnName}`
    lines.push(`-- 🔗 FK Ekle: [${rel.fkColumnName}] → [${rel.referencedTable}]`)
    lines.push(`ALTER TABLE ${fullTableName}`)
    lines.push(`    ADD CONSTRAINT [${cname}]`)
    lines.push(`    FOREIGN KEY ([${rel.fkColumnName}])`)
    lines.push(`    REFERENCES [dbo].[${rel.referencedTable}] ([${rel.referencedColumn || 'Id'}])`)
    lines.push(`    ON DELETE ${fkCascadeSql(rel.cascadeDelete)}`)
    lines.push(`    ON UPDATE ${fkCascadeSql(rel.cascadeUpdate)};`)
    lines.push('')
  }

  const origRelById = new Map<string, SqlTableRelation>()
  originalRelationships.forEach((r) => origRelById.set(r.id, r))
  const curRelById = new Map<string, SqlTableRelation>()
  relationships.forEach((r) => curRelById.set(r.id, r))

  // Removed FKs → DROP CONSTRAINT
  originalRelationships.forEach((orig) => {
    if (!curRelById.has(orig.id)) {
      hasChanges = true
      const cname = orig.constraintName ?? `FK_${tableName}_${orig.fkColumnName}`
      lines.push(`-- ❌ FK Kaldır: [${orig.constraintName ?? cname}]`)
      lines.push(`ALTER TABLE ${fullTableName}`)
      lines.push(`    DROP CONSTRAINT [${cname}];`)
      lines.push('')
    }
  })

  // Changed FKs → DROP old + ADD new
  relationships.forEach((rel) => {
    if (!rel.fkColumnName.trim() || !rel.referencedTable.trim()) return
    const orig = origRelById.get(rel.id)
    if (orig) {
      // Existing FK — check if anything changed
      const changed =
        orig.fkColumnName !== rel.fkColumnName ||
        orig.referencedTable !== rel.referencedTable ||
        orig.referencedColumn !== rel.referencedColumn ||
        orig.cascadeDelete !== rel.cascadeDelete ||
        orig.cascadeUpdate !== rel.cascadeUpdate
      if (changed) {
        hasChanges = true
        const cname = orig.constraintName ?? `FK_${tableName}_${orig.fkColumnName}`
        lines.push(`-- ✏️ FK Güncelle (drop + re-add): [${cname}]`)
        lines.push(`ALTER TABLE ${fullTableName}`)
        lines.push(`    DROP CONSTRAINT [${cname}];`)
        lines.push('')
        addFkSql(rel)
      }
    } else {
      // New FK
      hasChanges = true
      addFkSql(rel)
    }
  })

  // 🔑 Index / Key Diff
  const origIdxById = new Map<string, TableIndex>()
  originalIndexes.forEach((ix) => origIdxById.set(ix.id, ix))
  const curIdxById = new Map<string, TableIndex>()
  indexes.forEach((ix) => curIdxById.set(ix.id, ix))

  const dropIndexSql = (ix: TableIndex) => {
    if (ix.indexType === 'PrimaryKey' || ix.indexType === 'UniqueKey') {
      lines.push(`-- ❌ Kaldır: [${ix.indexName}]`)
      lines.push(`ALTER TABLE ${fullTableName}`)
      lines.push(`    DROP CONSTRAINT [${ix.indexName}];`)
    } else {
      lines.push(`-- ❌ Kaldır: [${ix.indexName}]`)
      lines.push(`DROP INDEX [${ix.indexName}] ON ${fullTableName};`)
    }
    lines.push('')
  }

  const addIndexSql = (ix: TableIndex) => {
    if (ix.columns.length === 0) return
    const clustered = ix.isClustered ? 'CLUSTERED' : 'NONCLUSTERED'
    const colsSql = ix.columns.map((c) => `[${c.columnName}] ${c.order}`).join(', ')
    if (ix.indexType === 'PrimaryKey') {
      lines.push(`-- 🔑 Primary Key: [${ix.indexName}]`)
      lines.push(`ALTER TABLE ${fullTableName}`)
      lines.push(`    ADD CONSTRAINT [${ix.indexName}] PRIMARY KEY ${clustered} (${colsSql});`)
    } else if (ix.indexType === 'UniqueKey') {
      lines.push(`-- 🔒 Unique Key: [${ix.indexName}]`)
      lines.push(`ALTER TABLE ${fullTableName}`)
      lines.push(`    ADD CONSTRAINT [${ix.indexName}] UNIQUE ${clustered} (${colsSql});`)
    } else {
      lines.push(`-- 📋 Index: [${ix.indexName}]`)
      lines.push(
        `CREATE ${ix.isClustered ? 'CLUSTERED ' : ''}INDEX [${ix.indexName}] ON ${fullTableName} (${colsSql});`,
      )
    }
    lines.push('')
  }

  // Removed indexes
  originalIndexes.forEach((orig) => {
    if (!curIdxById.has(orig.id)) {
      hasChanges = true
      dropIndexSql(orig)
    }
  })

  // New and modified indexes
  indexes.forEach((cur) => {
    if (cur.columns.length === 0) return
    const orig = origIdxById.get(cur.id)
    if (!orig) {
      hasChanges = true
      addIndexSql(cur)
    } else {
      const changed =
        orig.indexName !== cur.indexName ||
        orig.indexType !== cur.indexType ||
        orig.isClustered !== cur.isClustered ||
        JSON.stringify(orig.columns) !== JSON.stringify(cur.columns)
      if (changed) {
        hasChanges = true
        lines.push(`-- ✏️ Index Güncelle (drop + re-create): [${orig.indexName}]`)
        dropIndexSql(orig)
        addIndexSql(cur)
      }
    }
  })

  if (!hasChanges) {
    lines.push(
      '/* ℹ️ Henüz değişiklik yapılmadı. Sütunları ekleyin/silin/düzeyin ya da ilişki/index ekleyin. */',
    )
  }

  return lines.join('\n')
}

const STEPS = ['Sütun Tasarımı', 'Entity Ayarları', 'Index / Key', 'İlişkiler', 'T-SQL Önizleme'] as const
type Step = 0 | 1 | 2 | 3 | 4

function StepContentWrapper({ children }: { children: React.ReactNode }) {
  const { isMaximized } = useDialogContext()
  return (
    <div className={isMaximized ? 'flex-1 min-h-0 overflow-auto' : 'min-h-[420px]'}>
      {children}
    </div>
  )
}

// ─── Simple Menu Tree (read-only selection) ───────────────────────────────────

interface SimpleMenuTreeNodeProps {
  node: MenuTreeNode & { shortName?: string }
  depth: number
  selectedCode: string
  onSelect: (code: string) => void
  expanded: Set<string>
  onToggle: (code: string) => void
}

function SimpleMenuTreeNode({
  node,
  depth,
  selectedCode,
  onSelect,
  expanded,
  onToggle,
}: SimpleMenuTreeNodeProps) {
  const hasChildren = node.children.length > 0
  const isExpanded = expanded.has(node.code)
  const isSelected = node.code === selectedCode
  const NodeIcon = node.icon ? navigationIcon[node.icon] : null
  const { translate } = useLocalization()

  return (
    <div>
      <div
        className={`flex items-center gap-1 px-2 py-1.5 rounded mx-1 cursor-pointer ${
          isSelected
            ? 'bg-indigo-500 text-white'
            : 'hover:bg-gray-100 dark:hover:bg-gray-700 text-gray-700 dark:text-gray-200'
        }`}
        style={{ paddingLeft: `${8 + depth * 16}px` }}
        onClick={() => onSelect(node.code)}
      >
        <span>
          {hasChildren ? (
            isExpanded ? (
              <FaChevronDown className="text-gray-400" />
            ) : (
              <FaChevronRight className="text-gray-400" />
            )
          ) : null}
        </span>
        {NodeIcon && (
          <NodeIcon
            className={`text-base shrink-0 ${isSelected ? 'text-indigo-200' : 'text-gray-400'}`}
          />
        )}
        <span className="flex-1 text-sm truncate">{translate('::' + node.code)}</span>
        {node.shortName && (
          <span
            className={`text-xs shrink-0 font-mono px-1.5 py-0.5 rounded ${
              isSelected
                ? 'bg-indigo-400 text-indigo-100'
                : 'bg-gray-100 dark:bg-gray-700 text-gray-500 dark:text-gray-400'
            }`}
          >
            {node.shortName}
          </span>
        )}
      </div>
      {isExpanded &&
        node.children.map((child: MenuTreeNode) => (
          <SimpleMenuTreeNode
            key={child.code}
            node={child as MenuTreeNode & { shortName?: string }}
            depth={depth + 1}
            selectedCode={selectedCode}
            onSelect={onSelect}
            expanded={expanded}
            onToggle={onToggle}
          />
        ))}
    </div>
  )
}

interface SimpleMenuTreeSelectProps {
  selectedCode: string
  onSelect: (code: string) => void
  nodes: MenuTreeNode[]
  isLoading: boolean
  invalid?: boolean
}

function SimpleMenuTreeSelect({
  selectedCode,
  onSelect,
  nodes,
  isLoading,
  invalid,
}: SimpleMenuTreeSelectProps) {
  const [expanded, setExpanded] = useState<Set<string>>(new Set())

  const toggle = (code: string) =>
    setExpanded((prev) => {
      const n = new Set(prev)
      n.has(code) ? n.delete(code) : n.add(code)
      return n
    })

  return (
    <div
      className={`rounded-lg border ${
        invalid ? 'border-red-500' : 'border-gray-300 dark:border-gray-600'
      } bg-white dark:bg-gray-800 overflow-hidden`}
    >
      <div className="h-56 overflow-y-auto py-1">
        {isLoading ? (
          <div className="px-4 py-3 text-sm text-gray-400">Loading…</div>
        ) : nodes.length === 0 ? (
          <div className="px-4 py-3 text-sm text-gray-400">No menus available</div>
        ) : (
          nodes.map((node) => (
            <SimpleMenuTreeNode
              key={node.code}
              node={node as MenuTreeNode & { shortName?: string }}
              depth={0}
              selectedCode={selectedCode}
              onSelect={onSelect}
              expanded={expanded}
              onToggle={toggle}
            />
          ))
        )}
      </div>
    </div>
  )
}

const createEmptyColumn = (): ColumnDefinition => ({
  id: crypto.randomUUID(),
  columnName: '',
  dataType: 'nvarchar',
  maxLength: '100',
  isNullable: true,
  defaultValue: '',
  description: '',
})

const DEFAULT_SETTINGS: TableSettings = {
  menuValue: '',
  menuPrefix: '',
  entityName: '',
  tableName: '',
}

// ─── Component ────────────────────────────────────────────────────────────────

const SqlTableDesignerDialog = ({
  isOpen,
  onClose,
  dataSource,
  onDeployed,
  initialTableData,
}: TableDesignerDialogProps) => {
  const { translate } = useLocalization()

  const isEditMode = !!initialTableData

  const [step, setStep] = useState<Step>(0)
  const [isDeploying, setIsDeploying] = useState(false)
  const [columns, setColumns] = useState<ColumnDefinition[]>([createEmptyColumn()])
  const [originalColumns, setOriginalColumns] = useState<ColumnDefinition[]>([])
  const [colsLoading, setColsLoading] = useState(false)
  const [settings, setSettings] = useState<TableSettings>(DEFAULT_SETTINGS)
  const [rawMenuItems, setRawMenuItems] = useState<MenuItem[]>([])
  const [menuTree, setMenuTree] = useState<MenuTreeNode[]>([])
  const [selectedMenuCode, setSelectedMenuCode] = useState('')
  const [menuAddDialogOpen, setMenuAddDialogOpen] = useState(false)
  const [menuLoading, setMenuLoading] = useState(false)
  const [relationships, setRelationships] = useState<SqlTableRelation[]>([])
  const [originalRelationships, setOriginalRelationships] = useState<SqlTableRelation[]>([])
  const [fksLoading, setFksLoading] = useState(false)
  const [fkModalOpen, setFkModalOpen] = useState(false)
  const [editingFkId, setEditingFkId] = useState<string | null>(null)
  const [fkForm, setFkForm] = useState<Omit<SqlTableRelation, 'id'>>(EMPTY_FK)
  const [dbTables, setDbTables] = useState<{ schemaName: string; tableName: string }[]>([])
  const [targetTableColumns, setTargetTableColumns] = useState<string[]>([])
  const [targetTableKeyColumns, setTargetTableKeyColumns] = useState<string[]>([])
  const [targetColsLoading, setTargetColsLoading] = useState(false)
  const [indexes, setIndexes] = useState<TableIndex[]>([])
  const [originalIndexes, setOriginalIndexes] = useState<TableIndex[]>([])
  const [indexesLoading, setIndexesLoading] = useState(false)
  const [indexModalOpen, setIndexModalOpen] = useState(false)
  const [editingIndexId, setEditingIndexId] = useState<string | null>(null)
  const [indexForm, setIndexForm] = useState<Omit<TableIndex, 'id'>>(EMPTY_INDEX)

  const reloadMenus = (onLoaded?: (items: MenuItem[]) => void) => {
    setMenuLoading(true)
    getMenus(0, 1000)
      .then((res) => {
        const items = (res.data?.items ?? []) as MenuItem[]
        const filtered = items.filter((m) => !!m.shortName?.trim())
        setRawMenuItems(filtered)
        const tree = filterNonLinkNodes(buildMenuTree(filtered))
        setMenuTree(tree)
        onLoaded?.(filtered)
      })
      .catch(() => {})
      .finally(() => setMenuLoading(false))
  }

  useEffect(() => {
    if (!isOpen) return
    reloadMenus((items) => {
      // In edit mode, auto-select the matching menu code by shortName
      if (initialTableData) {
        const parts = initialTableData.tableName.split('_')
        const derivedShortName = parts[0] ?? ''
        const match = items.find((m) => m.shortName === derivedShortName)
        if (match?.code) setSelectedMenuCode(match.code)
      }
    })

    if (dataSource) {
      sqlObjectManagerService
        .getAllObjects(dataSource)
        .then((res) => setDbTables(res.data?.tables ?? []))
        .catch(() => {})
    }

    // Edit mode: load table's existing columns + FK constraints
    if (initialTableData && dataSource) {
      setColsLoading(true)
      sqlObjectManagerService
        .getTableColumns(dataSource, initialTableData.schemaName, initialTableData.tableName)
        .then((res) => {
          const defs = (res.data ?? []).map(dbColToColumnDef)
          setColumns(defs.length > 0 ? defs : [createEmptyColumn()])
          setOriginalColumns(defs)
          setSettings((s) => ({ ...s, tableName: initialTableData.tableName }))
        })
        .catch(() => {})
        .finally(() => setColsLoading(false))

      // Derive settings from table name (e.g. "Sas_D_EntityName" → menu: "Sas", entity: "EntityName")
      const parts = initialTableData.tableName.split('_')
      const derivedMenu = parts[0] ?? ''
      const derivedEntity = parts[parts.length - 1] ?? initialTableData.tableName
      setSettings((s) => ({
        ...s,
        menuValue: derivedMenu,
        menuPrefix: derivedMenu,
        entityName: derivedEntity,
        displayName: derivedEntity,
      }))

      // Load existing FK constraints
      const fkQuery = [
        'SELECT',
        '  fk.name AS constraintName,',
        '  col.name AS fkColumnName,',
        '  ref_t.name AS referencedTable,',
        '  ref_c.name AS referencedColumn,',
        '  fk.delete_referential_action_desc AS cascadeDelete,',
        '  fk.update_referential_action_desc AS cascadeUpdate',
        'FROM sys.foreign_keys fk',
        'INNER JOIN sys.foreign_key_columns fkc ON fk.object_id = fkc.constraint_object_id',
        'INNER JOIN sys.columns col ON fkc.parent_object_id = col.object_id AND fkc.parent_column_id = col.column_id',
        'INNER JOIN sys.tables ref_t ON fkc.referenced_object_id = ref_t.object_id',
        'INNER JOIN sys.columns ref_c ON fkc.referenced_object_id = ref_c.object_id AND fkc.referenced_column_id = ref_c.column_id',
        `WHERE fk.parent_object_id = OBJECT_ID('${initialTableData.schemaName}.${initialTableData.tableName}')`,
      ].join('\n')

      const mapCascade = (v: string): CascadeBehavior => {
        if (v === 'CASCADE') return 'Cascade'
        if (v === 'SET_NULL') return 'SetNull'
        if (v === 'SET_DEFAULT') return 'Restrict'
        return 'NoAction'
      }

      setFksLoading(true)
      sqlObjectManagerService
        .executeQuery({ queryText: fkQuery, dataSourceCode: dataSource })
        .then((res) => {
          const rows: any[] = res.data?.data ?? []
          const fkDefs: SqlTableRelation[] = rows.map((r) => ({
            id: crypto.randomUUID(),
            constraintName: r.constraintName,
            relationshipType: 'OneToMany' as RelationshipType,
            fkColumnName: r.fkColumnName,
            referencedTable: r.referencedTable,
            referencedColumn: r.referencedColumn,
            cascadeDelete: mapCascade(r.cascadeDelete),
            cascadeUpdate: mapCascade(r.cascadeUpdate),
            isRequired: false,
            description: '',
          }))
          setRelationships(fkDefs)
          setOriginalRelationships(fkDefs)
        })
        .catch(() => {})
        .finally(() => setFksLoading(false))

      // Load existing indexes / keys
      const idxQuery = [
        'SELECT',
        '  i.name AS indexName,',
        '  CASE',
        "    WHEN i.is_primary_key = 1 THEN 'PrimaryKey'",
        "    WHEN i.is_unique_constraint = 1 THEN 'UniqueKey'",
        "    ELSE 'Index'",
        '  END AS indexType,',
        '  CAST(CASE WHEN i.type = 1 THEN 1 ELSE 0 END AS BIT) AS isClustered,',
        '  col.name AS columnName,',
        '  ic.is_descending_key AS isDescending,',
        '  ic.key_ordinal AS keyOrdinal',
        'FROM sys.indexes i',
        'INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id',
        'INNER JOIN sys.columns col ON ic.object_id = col.object_id AND ic.column_id = col.column_id',
        `WHERE i.object_id = OBJECT_ID('${initialTableData.schemaName}.${initialTableData.tableName}')`,
        '  AND ic.is_included_column = 0',
        'ORDER BY i.name, ic.key_ordinal',
      ].join('\n')

      setIndexesLoading(true)
      sqlObjectManagerService
        .executeQuery({ queryText: idxQuery, dataSourceCode: dataSource })
        .then((res) => {
          const rows: any[] = res.data?.data ?? []
          const idxMap = new Map<string, TableIndex>()
          rows.forEach((row) => {
            if (!idxMap.has(row.indexName)) {
              idxMap.set(row.indexName, {
                id: crypto.randomUUID(),
                indexName: row.indexName,
                indexType: row.indexType as IndexType,
                isClustered: row.isClustered === true || row.isClustered === 1,
                columns: [],
                description: '',
              })
            }
            idxMap.get(row.indexName)!.columns.push({
              columnName: row.columnName,
              order: row.isDescending ? 'DESC' : 'ASC',
            })
          })
          const idxDefs = Array.from(idxMap.values())
          setIndexes(idxDefs)
          setOriginalIndexes(idxDefs)
        })
        .catch(() => {})
        .finally(() => setIndexesLoading(false))
    }
  }, [isOpen, dataSource, initialTableData])

  const generatedSql = useMemo(
    () =>
      isEditMode
        ? generateAlterTableSql(
            originalColumns,
            columns,
            settings.tableName || initialTableData?.tableName || '',
            relationships,
            originalRelationships,
            indexes,
            originalIndexes,
          )
        : generateCreateTableSql(columns, settings, relationships, indexes),
    [
      isEditMode,
      originalColumns,
      columns,
      settings,
      initialTableData,
      relationships,
      originalRelationships,
      indexes,
      originalIndexes,
    ],
  )

  // ── Column operations ──────────────────────────────────────────────────────

  const [newRowId, setNewRowId] = useState<string | null>(null)

  const addColumn = () => {
    const col = createEmptyColumn()
    setColumns((prev) => [...prev, col])
    setNewRowId(col.id)
  }

  const clearAllColumns = () => setColumns([createEmptyColumn()])

  const addFullAuditedColumns = () => {
    const existingNames = new Set(columns.map((c) => c.columnName.trim().toLowerCase()))
    const toAdd = FULL_AUDIT_COLUMNS.filter((c) => !existingNames.has(c.columnName.toLowerCase()))
    setColumns((prev) => {
      const nonEmpty = prev.filter((c) => c.columnName.trim() !== '')
      return [...nonEmpty, ...toAdd.map((c) => ({ ...c })), createEmptyColumn()]
    })

    // FullAudited ile Id eklendiğinde PK tanımı Index/Key listesine otomatik düşsün.
    setIndexes((prev) => {
      const hasPk = prev.some((ix) => ix.indexType === 'PrimaryKey')
      if (hasPk) return prev

      const tableName = settings.tableName || initialTableData?.tableName || 'Table'
      return [
        ...prev,
        {
          id: `auto-pk-${crypto.randomUUID()}`,
          indexName: `PK_${tableName}`,
          indexType: 'PrimaryKey',
          isClustered: false,
          columns: [{ columnName: 'Id', order: 'ASC' }],
          description: 'Primary key (auto)',
        },
      ]
    })
  }

  const addMultiTenantColumns = () => {
    const existingNames = new Set(columns.map((c) => c.columnName.trim().toLowerCase()))
    if (!existingNames.has(TENANT_COLUMN.columnName.toLowerCase())) {
      setColumns((prev) => {
        const nonEmpty = prev.filter((c) => c.columnName.trim() !== '')
        return [...nonEmpty, { ...TENANT_COLUMN }, createEmptyColumn()]
      })
    }
  }

  const importColumnsFromRememberedCreateTable = async () => {
    let script = ''

    try {
      const clipboardText = await navigator.clipboard.readText()
      if (/\bCREATE\s+TABLE\b/i.test(clipboardText)) {
        script = clipboardText
        localStorage.setItem(CREATE_TABLE_SCRIPT_STORAGE_KEY, clipboardText)
      }
    } catch {
      // Clipboard read can fail due to browser permissions; fallback to saved script.
    }

    if (!script) {
      script = localStorage.getItem(CREATE_TABLE_SCRIPT_STORAGE_KEY) || ''
    }

    if (!script.trim()) {
      toast.push(
        <Notification type="warning" title={translate('::App.Platform.Warning')}>
          CREATE TABLE script bulunamadı. Scripti panoya kopyalayıp tekrar deneyin.
        </Notification>,
        { placement: 'top-center' },
      )
      return
    }

    const parsedColumns = parseCreateTableColumns(script)
    if (parsedColumns.length === 0) {
      toast.push(
        <Notification type="warning" title={translate('::App.Platform.Warning')}>
          CREATE TABLE scriptinden sütunlar ayrıştırılamadı.
        </Notification>,
        { placement: 'top-center' },
      )
      return
    }

    let addedCount = 0
    let skippedCount = 0

    setColumns((prev) => {
      const existingNonEmpty = prev.filter((c) => c.columnName.trim() !== '')
      const existingNames = new Set(
        existingNonEmpty.map((c) => c.columnName.trim().toLowerCase()),
      )

      const toAdd: ColumnDefinition[] = []
      for (const col of parsedColumns) {
        const key = col.columnName.trim().toLowerCase()
        if (!key) {
          skippedCount++
          continue
        }

        if (existingNames.has(key)) {
          skippedCount++
          continue
        }

        existingNames.add(key)
        toAdd.push(col)
      }

      addedCount = toAdd.length
      return [...existingNonEmpty, ...toAdd, createEmptyColumn()]
    })

    toast.push(
      <Notification type="success" title={translate('::App.Platform.Success')}>
        {addedCount > 0
          ? `${addedCount} sütun eklendi${skippedCount > 0 ? `, ${skippedCount} sütun zaten mevcut olduğu için atlandı.` : '.'}`
          : 'Yeni sütun eklenmedi. Scriptteki sütunların tamamı zaten mevcut.'}
      </Notification>,
      { placement: 'top-center' },
    )
  }

  const removeColumn = (id: string) => setColumns((prev) => prev.filter((c) => c.id !== id))

  const moveColumn = (id: string, direction: 'up' | 'down') => {
    setColumns((prev) => {
      const idx = prev.findIndex((c) => c.id === id)
      if (idx < 0) return prev
      const next = [...prev]
      const swap = direction === 'up' ? idx - 1 : idx + 1
      if (swap < 0 || swap >= next.length) return prev
      ;[next[idx], next[swap]] = [next[swap], next[idx]]
      return next
    })
  }

  const updateColumn = useCallback(
    <K extends keyof ColumnDefinition>(id: string, field: K, value: ColumnDefinition[K]) => {
      setColumns((prev) => prev.map((c) => (c.id === id ? { ...c, [field]: value } : c)))
    },
    [],
  )

  // ── Settings helpers ───────────────────────────────────────────────────────

  const hasTenantIdColumn = (cols: ColumnDefinition[]) =>
    cols.some((c) => c.columnName.trim().toLowerCase() === 'tenantid')

  const buildTableName = (prefix: string, entity: string) =>
    prefix && entity ? `${prefix}_${hasTenantIdColumn(columns) ? 'T' : 'D'}_${entity}` : ''

  const syncAutoPkName = (newTableName: string) => {
    if (!newTableName) return
    setIndexes((prev) =>
      prev.map((ix) =>
        ix.indexType === 'PrimaryKey' && ix.id.startsWith('auto-pk')
          ? { ...ix, indexName: `PK_${newTableName}` }
          : ix,
      ),
    )
  }

  const onMenuCodeSelect = (code: string) => {
    if (isEditMode) return
    const item = rawMenuItems.find((m) => m.code === code)
    const prefix = item?.shortName ?? ''
    setSelectedMenuCode(code)
    const newTableName = buildTableName(prefix, settings.entityName)
    setSettings((s) => ({
      ...s,
      menuValue: prefix,
      menuPrefix: prefix,
      tableName: newTableName,
    }))
    syncAutoPkName(newTableName)
  }

  // Strip spaces and special chars — only alphanumeric + underscore allowed
  const onEntityNameChange = (value: string) => {
    const sanitized = value.replace(/[^A-Za-z0-9_]/g, '')
    const newTableName = buildTableName(settings.menuPrefix, sanitized)
    setSettings((s) => ({
      ...s,
      entityName: sanitized,
      tableName: newTableName,
      displayName: sanitized, // always mirrors entity name
    }))
    syncAutoPkName(newTableName)
  }

  useEffect(() => {
    if (isEditMode) return
    if (!settings.menuPrefix || !settings.entityName) return

    const recalculatedTableName = buildTableName(settings.menuPrefix, settings.entityName)
    if (!recalculatedTableName || recalculatedTableName === settings.tableName) return

    setSettings((s) => ({ ...s, tableName: recalculatedTableName }))
    syncAutoPkName(recalculatedTableName)
  }, [
    isEditMode,
    columns,
    settings.menuPrefix,
    settings.entityName,
    settings.tableName,
  ])

  // ── FK Relationship handlers ───────────────────────────────────────────────

  const loadTargetColumns = (tableName: string) => {
    if (!tableName || !dataSource) {
      setTargetTableColumns([])
      setTargetTableKeyColumns([])
      return
    }
    const tbl = dbTables.find((t) => t.tableName === tableName)
    if (!tbl) return
    setTargetColsLoading(true)
    const objectName = `[${tbl.schemaName}].[${tbl.tableName}]`
    const keyColsQuery = [
      'SELECT DISTINCT c.name AS columnName',
      'FROM sys.indexes i',
      'INNER JOIN sys.index_columns ic ON i.object_id = ic.object_id AND i.index_id = ic.index_id',
      'INNER JOIN sys.columns c ON ic.object_id = c.object_id AND ic.column_id = c.column_id',
      `WHERE i.object_id = OBJECT_ID('${objectName}')`,
      '  AND ic.is_included_column = 0',
      '  AND (i.is_primary_key = 1 OR i.is_unique = 1 OR i.is_unique_constraint = 1)',
      'ORDER BY c.name',
    ].join('\n')

    Promise.all([
      sqlObjectManagerService.getTableColumns(dataSource, tbl.schemaName, tbl.tableName),
      sqlObjectManagerService.executeQuery({ queryText: keyColsQuery, dataSourceCode: dataSource }),
    ])
      .then(([colsRes, keyColsRes]) => {
        const allCols = (colsRes.data ?? []).map((c) => c.columnName)
        const keyCols = ((keyColsRes.data?.data ?? []) as any[]).map((r) => r.columnName)
        setTargetTableColumns(allCols)
        setTargetTableKeyColumns(keyCols)
      })
      .catch(() => {
        setTargetTableColumns([])
        setTargetTableKeyColumns([])
      })
      .finally(() => setTargetColsLoading(false))
  }

  const openAddFk = () => {
    setEditingFkId(null)
    setFkForm(EMPTY_FK)
    setTargetTableColumns([])
    setTargetTableKeyColumns([])
    setFkModalOpen(true)
  }

  const openEditFk = (rel: SqlTableRelation) => {
    setEditingFkId(rel.id)
    const { id: _id, ...rest } = rel
    setFkForm(rest)
    loadTargetColumns(rest.referencedTable)
    setFkModalOpen(true)
  }

  const saveFk = () => {
    if (!fkForm.fkColumnName.trim() || !fkForm.referencedTable.trim() || !fkForm.referencedColumn.trim()) {
      return
    }

    const isTargetKeyColumn = targetTableKeyColumns.some(
      (c) => c.toLowerCase() === fkForm.referencedColumn.trim().toLowerCase(),
    )
    if (!isTargetKeyColumn) {
      toast.push(
        <Notification type="warning" title={translate('::App.SqlQueryManager.Warning')}>
          Referans kolon PK/UNIQUE olmalı. Lütfen hedef tablodan anahtar bir kolon seçin.
        </Notification>,
        { placement: 'top-center' },
      )
      return
    }

    if (editingFkId) {
      setRelationships((prev) =>
        prev.map((r) => (r.id === editingFkId ? { ...fkForm, id: editingFkId } : r)),
      )
    } else {
      setRelationships((prev) => [...prev, { ...fkForm, id: crypto.randomUUID() }])
    }
    setFkModalOpen(false)
  }

  const deleteFk = (id: string) => {
    setRelationships((prev) => prev.filter((r) => r.id !== id))
  }

  // ── Index / Key handlers ─────────────────────────────────────────────────

  const buildIndexName = (type: IndexType, cols: IndexColumnEntry[]): string => {
    const prefix = type === 'PrimaryKey' ? 'PK' : type === 'UniqueKey' ? 'UQ' : 'IX'
    const entityName = settings.entityName || initialTableData?.tableName || ''
    const colPart = cols.map((c) => c.columnName).join('_')
    if (entityName && colPart) return `${prefix}_${entityName}_${colPart}`
    if (entityName) return `${prefix}_${entityName}`
    if (colPart) return `${prefix}_${colPart}`
    return prefix
  }

  const openAddIndex = () => {
    setEditingIndexId(null)
    const entityName = settings.entityName || initialTableData?.tableName || ''
    setIndexForm({ ...EMPTY_INDEX, indexName: entityName ? `IX_${entityName}` : '' })
    setIndexModalOpen(true)
  }

  const openEditIndex = (idx: TableIndex) => {
    setEditingIndexId(idx.id)
    const { id: _id, ...rest } = idx
    setIndexForm(rest)
    setIndexModalOpen(true)
  }

  const saveIndex = () => {
    if (!indexForm.indexName.trim() || indexForm.columns.length === 0) return
    if (editingIndexId) {
      setIndexes((prev) =>
        prev.map((ix) => (ix.id === editingIndexId ? { ...indexForm, id: editingIndexId } : ix)),
      )
    } else {
      setIndexes((prev) => [...prev, { ...indexForm, id: crypto.randomUUID() }])
    }
    setIndexModalOpen(false)
  }

  const deleteIndex = (id: string) => {
    setIndexes((prev) => prev.filter((ix) => ix.id !== id))
  }

  // ── Navigation ─────────────────────────────────────────────────────────────

  // Compute duplicate column names (lowercased)
  const duplicateColumnNames = useMemo(() => {
    const names = columns.map((c) => c.columnName.trim().toLowerCase()).filter(Boolean)
    return new Set(names.filter((n, i) => names.indexOf(n) !== i))
  }, [columns])

  const canGoNext = (): boolean => {
    if (step === 0) {
      const hasNamed = columns.some((c) => c.columnName.trim().length > 0)
      return hasNamed && duplicateColumnNames.size === 0
    }
    if (step === 1) {
      if (isEditMode) return true // table name is locked in edit mode
      const baseOk =
        !!settings.tableName.trim() && !!settings.entityName.trim() && !!settings.menuValue
      return baseOk
    }
    return true
  }

  const handleNext = () => {
    if (step < 4) setStep((s) => (s + 1) as Step)
  }
  const handleBack = () => {
    if (step > 0) setStep((s) => (s - 1) as Step)
  }

  // ── Deploy ─────────────────────────────────────────────────────────────────

  const handleDeploy = async () => {
    if (!dataSource) {
      toast.push(
        <Notification type="warning" title={translate('::App.SqlQueryManager.Warning')}>
          {translate('::App.SqlQueryManager.PleaseSelectDataSource')}
        </Notification>,
        { placement: 'top-center' },
      )
      return
    }
    setIsDeploying(true)
    try {
      // Strip GO batch separators — they are SSMS-only and not valid T-SQL
      const executableSql = generatedSql
        .split(/^\s*GO\s*$/im)
        .map((b) => b.trim())
        .filter(Boolean)
        .join('\n')

      const result = await sqlObjectManagerService.executeQuery({
        queryText: executableSql,
        dataSourceCode: dataSource,
      })
      if (result.data.success) {
        const deployedTable = settings.tableName || initialTableData?.tableName || ''
        toast.push(
          <Notification type="success" title={translate('::App.Platform.Success')}>
            {`${translate(isEditMode ? '::App.SqlQueryManager.TableUpdated' : '::App.SqlQueryManager.TableCreated')}: [dbo].[${deployedTable}]`}
          </Notification>,
          { placement: 'top-center' },
        )
        // Save seed file to DbMigrator/Seeds/SqlData after successful deploy.
        // Always use the full CREATE TABLE script (not the ALTER diff) so the seed file
        // can recreate the table from scratch when the database is wiped.
        try {
          const seedSql = generateCreateTableSql(columns, settings, relationships, indexes)
          await sqlObjectManagerService.saveTableScript({
            fileName: deployedTable,
            sqlScript: seedSql,
          })
        } catch {
          // Non-blocking: seed file save failure does not affect deploy success
        }
        onDeployed?.()
        handleClose()
      } else {
        toast.push(
          <Notification type="danger" title={translate('::App.Platform.Error')}>
            {result.data.message || translate('::App.SqlQueryManager.TableCreationFailed')}
          </Notification>,
          { placement: 'top-center' },
        )
      }
    } catch (error: any) {
      toast.push(
        <Notification type="danger" title={translate('::App.Platform.Error')}>
          {error.response?.data?.error?.message ||
            translate('::App.SqlQueryManager.TableDeployFailed')}
        </Notification>,
        { placement: 'top-center' },
      )
    } finally {
      setIsDeploying(false)
    }
  }

  const handleClose = () => {
    setStep(0)
    setColumns([createEmptyColumn()])
    setOriginalColumns([])
    setSettings(DEFAULT_SETTINGS)
    setRelationships([])
    setOriginalRelationships([])
    setIndexes([])
    setOriginalIndexes([])
    setDbTables([])
    setTargetTableColumns([])
    setTargetTableKeyColumns([])
    setSelectedMenuCode('')
    setMenuAddDialogOpen(false)
    onClose()
  }

  // ── Step Indicator ─────────────────────────────────────────────────────────

  const STEP_LABELS = [
    translate('::App.SqlQueryManager.ColumnDesign'),
    translate('::App.SqlQueryManager.EntitySettings'),
    translate('::App.SqlQueryManager.IndexKeys'), 
    translate('::App.SqlQueryManager.Relationships'),
    translate('::App.SqlQueryManager.TSqlPreview'),
  ]

  const renderStepIndicator = () => (
    <div className="flex items-center justify-between mb-2">
      {STEP_LABELS.map((label, i) => {
        const isDone = i < step
        const isActive = i === step
        return (
          <div key={i} className="flex items-center flex-1">
            <div className="flex items-center gap-2">
              <div
                className={`w-7 h-7 rounded-full flex items-center justify-center text-xs font-bold transition-colors
                  ${isDone ? 'bg-green-500 text-white' : isActive ? 'bg-blue-600 text-white' : 'bg-gray-200 text-gray-500 dark:bg-gray-700 dark:text-gray-400'}`}
              >
                {isDone ? <FaCheck /> : i + 1}
              </div>
              <span
                className={`text-sm font-medium whitespace-nowrap ${isActive ? 'text-blue-600 dark:text-blue-400' : 'text-gray-500'}`}
              >
                {label}
              </span>
            </div>
            {i < STEP_LABELS.length - 1 && (
              <div className="flex-1 mx-3 h-px bg-gray-200 dark:bg-gray-700" />
            )}
          </div>
        )
      })}
    </div>
  )

  // ── Step 0: Column Designer ────────────────────────────────────────────────

  const renderColumnDesigner = () => (
    <div className="flex flex-col">
      {colsLoading && (
        <div className="flex items-center justify-center py-12 text-gray-500">
          <span className="animate-spin mr-2">&#9696;</span>{' '}
          {translate('::App.SqlQueryManager.LoadingColumns')}
        </div>
      )}
      {!colsLoading && (
        <>
          <div className="flex items-center justify-between py-2">
            <div className="flex items-center gap-2">
              <Button size="xs" variant="solid" color="blue-600" onClick={addFullAuditedColumns}>
                {translate('::App.SqlQueryManager.AddFullAuditedColumns')}
              </Button>
              <Button size="xs" variant="solid" color="green-600" onClick={addMultiTenantColumns}>
                {translate('::App.SqlQueryManager.AddMultiTenantColumns')}
              </Button>
              <Button
                size="xs"
                variant="solid"
                color="amber-600"
                onClick={importColumnsFromRememberedCreateTable}
                disabled={isEditMode}
              >
                CREATE TABLE'dan Kolonları Yapıştır
              </Button>
            </div>
            <div className="flex items-center gap-2">
              <Button
                size="xs"
                variant="solid"
                color="red-600"
                icon={<FaTrash />}
                onClick={clearAllColumns}
              >
                {translate('::App.SqlQueryManager.ClearAllColumns')}
              </Button>
              <Button
                size="xs"
                variant="solid"
                color="blue-600"
                icon={<FaPlus />}
                onClick={addColumn}
              >
                {translate('::App.SqlQueryManager.AddColumn')}
              </Button>
            </div>
          </div>

          {/* Header row */}
          <div className="grid grid-cols-12 gap-1 px-1 py-1 bg-gray-50 dark:bg-gray-800 rounded text-xs font-semibold text-gray-600 dark:text-gray-300">
            <div className="col-span-4">{translate('::App.SqlQueryManager.ColumnName')}</div>
            <div className="col-span-3">{translate('::App.SqlQueryManager.DataType')}</div>
            <div className="col-span-1 text-center">{translate('::App.SqlQueryManager.Max')}</div>
            <div className="col-span-1 text-center">
              {translate('::App.SqlQueryManager.Nullable')}
            </div>
            <div className="col-span-2">{translate('::App.SqlQueryManager.DefaultValue')}</div>
            <div className="col-span-1 text-center">
              {translate('::App.SqlQueryManager.Actions')}
            </div>
          </div>

          {/* Editable column rows */}
          {duplicateColumnNames.size > 0 && (
            <div className="px-1 py-1.5 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded text-xs text-red-600 dark:text-red-400">
              ⚠️ Aynı isimde sütun tanımlanamaz:{' '}
              {[...duplicateColumnNames].map((n) => (
                <code key={n} className="bg-red-100 dark:bg-red-900/40 px-1 rounded mr-1">
                  {n}
                </code>
              ))}
            </div>
          )}

          <div className="flex flex-col gap-1 max-h-80 overflow-y-auto pr-1">
            {columns.map((col, idx) => {
              const isDuplicate =
                col.columnName.trim() !== '' &&
                duplicateColumnNames.has(col.columnName.trim().toLowerCase())
              const isNewRow = isEditMode && !originalColumns.some((o) => o.id === col.id)

              const origRow = isEditMode ? originalColumns.find((o) => o.id === col.id) : undefined
              const isRenamedRow =
                isEditMode &&
                !!origRow &&
                origRow.columnName.trim().toLowerCase() !== col.columnName.trim().toLowerCase()
              const isModifiedRow =
                isEditMode &&
                !!origRow &&
                !isNewRow &&
                (origRow.dataType !== col.dataType ||
                  origRow.maxLength !== col.maxLength ||
                  origRow.isNullable !== col.isNullable)

              const rowBg = isDuplicate
                ? 'outline outline-1 outline-red-400'
                : isNewRow
                  ? 'bg-green-50 dark:bg-green-900/20 outline outline-1 outline-green-400'
                  : isRenamedRow && isModifiedRow
                    ? 'bg-purple-50 dark:bg-purple-900/20 outline outline-1 outline-purple-400'
                    : isRenamedRow
                      ? 'bg-blue-50 dark:bg-blue-900/20 outline outline-1 outline-blue-400'
                      : isModifiedRow
                        ? 'bg-yellow-50 dark:bg-yellow-900/20 outline outline-1 outline-yellow-400'
                        : ''

              return (
                <div
                  key={col.id}
                  className={`grid grid-cols-12 gap-2 bg-white dark:bg-gray-800 rounded items-center ${rowBg}`}
                >
                  <div className="col-span-4">
                    <input
                      type="text"
                      className={`w-full px-2 py-1 text-sm border rounded dark:bg-gray-700 dark:border-gray-600 dark:text-white ${
                        isDuplicate ? 'border-red-400' : ''
                      }`}
                      placeholder={translate('::App.SqlQueryManager.ColumnNamePlaceholder')}
                      value={col.columnName}
                      onChange={(e) => updateColumn(col.id, 'columnName', e.target.value)}
                      ref={(el) => {
                        if (el && col.id === newRowId) {
                          el.focus()
                          setNewRowId(null)
                        }
                      }}
                    />
                  </div>
                  <div className="col-span-3">
                    <select
                      className="w-full px-2 py-1 text-sm border rounded dark:bg-gray-700 dark:border-gray-600 dark:text-white"
                      value={col.dataType}
                      onChange={(e) => {
                        const dt = e.target.value as SqlDataType
                        updateColumn(col.id, 'dataType', dt)
                        if (dt !== 'nvarchar') updateColumn(col.id, 'maxLength', '')
                        else if (!col.maxLength) updateColumn(col.id, 'maxLength', '100')
                      }}
                    >
                      {DATA_TYPES.map((t) => (
                        <option key={t.value} value={t.value}>
                          {t.label}
                        </option>
                      ))}
                    </select>
                  </div>
                  <div className="col-span-1">
                    <input
                      type="number"
                      className="w-full px-2 py-1 text-sm border rounded dark:bg-gray-700 dark:border-gray-600 dark:text-white text-center"
                      placeholder="-"
                      value={col.maxLength}
                      disabled={col.dataType !== 'nvarchar'}
                      onChange={(e) => updateColumn(col.id, 'maxLength', e.target.value)}
                    />
                  </div>
                  <div className="col-span-1 flex justify-center">
                    <Checkbox
                      checked={col.isNullable}
                      onChange={(checked) => updateColumn(col.id, 'isNullable', checked as boolean)}
                    />
                  </div>
                  <div className="col-span-2">
                    <input
                      type="text"
                      className="w-full px-2 py-1 text-sm border rounded dark:bg-gray-700 dark:border-gray-600 dark:text-white"
                      placeholder={translate('::App.SqlQueryManager.DefaultValue')}
                      value={col.defaultValue}
                      onChange={(e) => updateColumn(col.id, 'defaultValue', e.target.value)}
                    />
                  </div>
                  <div className="col-span-1 flex items-center justify-center gap-1">
                    <button
                      onClick={() => moveColumn(col.id, 'up')}
                      disabled={idx === 0}
                      className="p-1 rounded hover:bg-gray-100 dark:hover:bg-gray-700 disabled:opacity-30 text-gray-500"
                      title={translate('::App.SqlQueryManager.MoveUp')}
                    >
                      <FaArrowUp className="text-xs" />
                    </button>
                    <button
                      onClick={() => moveColumn(col.id, 'down')}
                      disabled={idx === columns.length - 1}
                      className="p-1 rounded hover:bg-gray-100 dark:hover:bg-gray-700 disabled:opacity-30 text-gray-500"
                      title={translate('::App.SqlQueryManager.MoveDown')}
                    >
                      <FaArrowDown className="text-xs" />
                    </button>
                    <button
                      onClick={() => removeColumn(col.id)}
                      className="p-1 rounded hover:bg-red-50 dark:hover:bg-red-900/30 text-red-500"
                      title={translate('::App.SqlQueryManager.Delete')}
                    >
                      <FaTrash className="text-xs" />
                    </button>
                  </div>
                </div>
              )
            })}
          </div>

          {/* PK guidance */}
          {!isEditMode && !columns.some((c) => c.columnName.trim().toLowerCase() === 'id') && (
            <div className="px-2 py-1.5 mt-2 bg-orange-50 dark:bg-orange-900/20 border border-orange-300 dark:border-orange-700 rounded text-xs text-orange-700 dark:text-orange-300">
              PK için Id kolonu (int veya uniqueidentifier) önerilir. İsterseniz bir sonraki adımda
              Primary Key de tanımlayabilirsiniz.
            </div>
          )}
        </>
      )}
    </div>
  )

  // ── Step 1: Entity Settings ────────────────────────────────────────────────

  const renderEntitySettings = () => (
    <div className="flex flex-col gap-2">
      <div className="grid grid-cols-2 gap-2">
        {/* Menu Name */}
        <div className="col-span-2">
          <div className="flex items-center justify-between mb-1">
            <label className="block text-sm font-medium">
              {translate('::App.SqlQueryManager.MenuName')} <span className="text-red-500">*</span>
            </label>
            <div className="flex items-center gap-2">
              <button
                type="button"
                disabled={isEditMode}
                onClick={() => setMenuAddDialogOpen(true)}
                className="flex items-center gap-1 px-2 py-0.5 text-xs rounded bg-green-500 text-white hover:bg-green-600 disabled:opacity-40 disabled:cursor-not-allowed"
              >
                <FaPlus className="text-xs" />{' '}
                {translate('::ListForms.Wizard.Step1.AddNewMenu') || 'Add Menu'}
              </button>
              {settings.menuValue && !isEditMode && (
                <button
                  type="button"
                  onClick={() => {
                    setSelectedMenuCode('')
                    setSettings((s) => ({ ...s, menuValue: '', menuPrefix: '', tableName: '' }))
                  }}
                  className="flex items-center gap-1 px-2 py-0.5 text-xs rounded border border-gray-300 dark:border-gray-600 text-gray-500 hover:text-red-500 hover:border-red-400"
                >
                  <FaTimes className="text-xs" />{' '}
                  {translate('::ListForms.Wizard.ClearSelection') || 'Clear'}
                </button>
              )}
            </div>
          </div>
          <SimpleMenuTreeSelect
            selectedCode={selectedMenuCode}
            onSelect={isEditMode ? () => {} : onMenuCodeSelect}
            nodes={menuTree}
            isLoading={menuLoading}
            invalid={!settings.menuValue && !isEditMode && !menuLoading}
          />
          {settings.menuValue && (
            <p className="text-xs text-gray-500 dark:text-gray-400 mt-1">
              <span className="font-mono font-semibold text-indigo-600 dark:text-indigo-400">
                {settings.menuValue}
              </span>
            </p>
          )}
          <MenuAddDialog
            isOpen={menuAddDialogOpen}
            onClose={() => setMenuAddDialogOpen(false)}
            initialParentCode={selectedMenuCode}
            initialOrder={999}
            rawItems={rawMenuItems}
            onSaved={() => reloadMenus()}
          />
        </div>

        {/* Entity Name */}
        <div>
          <label className="block text-sm font-medium mb-1">
            {translate('::App.SqlQueryManager.EntityName')} <span className="text-red-500">*</span>
          </label>
          <input
            type="text"
            disabled={isEditMode} // Entity name (and thus table name) cannot be changed in edit mode
            className="w-full px-3 py-2 text-sm border rounded dark:bg-gray-700 dark:border-gray-600 dark:text-white"
            value={settings.entityName}
            onChange={(e) => onEntityNameChange(e.target.value)}
            placeholder={translate('::App.SqlQueryManager.EntityNamePlaceholder')}
          />
        </div>

        {/* Table Name (readonly, auto-generated) */}
        <div>
          <label className="block text-sm font-medium mb-1">
            {translate('::App.Listform.ListformField.TableName')}
          </label>
          <input
            type="text"
            readOnly
            className="w-full px-3 py-2 text-sm border rounded bg-gray-50 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-300 cursor-not-allowed"
            value={isEditMode ? (initialTableData?.tableName ?? '') : settings.tableName}
            placeholder={translate('::App.SqlQueryManager.TableNameAutoGenerated')}
          />
        </div>
      </div>

      {/* Warning: no Id column */}
      {!isEditMode && !columns.some((c) => c.columnName.trim().toLowerCase() === 'id') && (
        <div className="px-3 py-2 bg-amber-50 dark:bg-amber-900/20 border border-amber-300 dark:border-amber-700 rounded text-xs text-amber-700 dark:text-amber-300">
          Full Audited kolonları seçmediğiniz için PK kolonu manuel tanımlanmalıdır. Bu kolon
          int veya uniqueidentifier olabilir.
        </div>
      )}
    </div>
  )

  // ── Step 2: Relationships ─────────────────────────────────────────────────

  const renderRelationships = () => (
    <div className="space-y-3">
      {/* Loading indicator for edit mode */}
      {fksLoading && (
        <div className="flex items-center justify-center py-10 text-gray-500 text-sm gap-2">
          <span className="animate-spin">&#9696;</span>{' '}
          {translate('::App.SqlQueryManager.LoadingFkConstraints')}
        </div>
      )}
      {!fksLoading && (
        <>
          {/* Header */}
          <div className="flex items-center justify-between">
            <span className="text-xs text-gray-500">
              {relationships.length === 0
                ? translate('::App.SqlQueryManager.NoRelationshipsDefined')
                : `${relationships.length} ${translate('::App.SqlQueryManager.Relationship')}`}
            </span>
            <button
              onClick={openAddFk}
              className="flex items-center gap-1 px-3 py-1.5 bg-indigo-600 hover:bg-indigo-700 text-white text-xs rounded-lg transition-colors"
            >
              <FaPlus className="w-2.5 h-2.5" />{' '}
              {translate('::App.SqlQueryManager.AddRelationship')}
            </button>
          </div>

          {/* Empty state */}
          {relationships.length === 0 && (
            <div className="py-8 text-center border-2 border-dashed border-gray-200 dark:border-gray-700 rounded-xl bg-gray-50 dark:bg-gray-800/50">
              <FaLink className="text-3xl mx-auto text-gray-300 dark:text-gray-600 mb-2" />
              <p className="text-sm text-gray-500">
                {translate('::App.SqlQueryManager.NoRelationshipsYet')}
              </p>
              <p className="text-xs text-gray-400 mt-1">
                {translate('::App.SqlQueryManager.StepIsOptional')}
              </p>
            </div>
          )}

          {/* Relationship cards */}
          <div className="space-y-2 max-h-72 overflow-y-auto pr-1">
            {relationships.map((rel) => (
              <div
                key={rel.id}
                className="border border-slate-200 dark:border-gray-700 rounded-xl px-4 py-3 flex items-start gap-3 bg-white dark:bg-gray-800"
              >
                <div className="p-2 rounded-lg mt-0.5 flex-shrink-0 bg-indigo-50 dark:bg-indigo-900/20 text-indigo-600 dark:text-indigo-400">
                  <FaLink className="w-3 h-3" />
                </div>
                <div className="flex-1 min-w-0">
                  <div className="flex items-center gap-2 flex-wrap">
                    <code className="text-sm font-semibold text-slate-900 dark:text-white">
                      [{rel.fkColumnName}]
                    </code>
                    <FaArrowRight className="w-3 h-3 text-gray-400 flex-shrink-0" />
                    <code className="text-sm font-semibold text-slate-900 dark:text-white">
                      [dbo].[{rel.referencedTable}].[{rel.referencedColumn || 'Id'}]
                    </code>
                    <span className="text-xs px-2 py-0.5 rounded-full bg-indigo-100 dark:bg-indigo-900/30 text-indigo-700 dark:text-indigo-300 font-medium">
                      {REL_TYPES.find((t) => t.value === rel.relationshipType)?.label}
                    </span>
                  </div>
                  <div className="flex items-center gap-3 mt-1 text-xs text-gray-500 flex-wrap">
                    <span>
                      ON DELETE: <strong>{rel.cascadeDelete}</strong>
                    </span>
                    <span>
                      ON UPDATE: <strong>{rel.cascadeUpdate}</strong>
                    </span>
                    {rel.isRequired && (
                      <span className="text-orange-600 dark:text-orange-400">
                        {translate('::App.SqlQueryManager.Required')}
                      </span>
                    )}
                    {rel.description && (
                      <span className="text-gray-400 italic">{rel.description}</span>
                    )}
                  </div>
                </div>
                <div className="flex items-center gap-1 flex-shrink-0">
                  <button
                    onClick={() => openEditFk(rel)}
                    title={translate('::App.SqlQueryManager.Edit')}
                    className="p-1.5 text-gray-400 hover:text-indigo-600 hover:bg-indigo-50 dark:hover:bg-indigo-900/20 rounded transition-colors"
                  >
                    <FaEdit className="w-3.5 h-3.5" />
                  </button>
                  <button
                    onClick={() => deleteFk(rel.id)}
                    title={translate('::App.SqlQueryManager.Delete')}
                    className="p-1.5 text-gray-400 hover:text-red-600 hover:bg-red-50 dark:hover:bg-red-900/20 rounded transition-colors"
                  >
                    <FaTrash className="w-3.5 h-3.5" />
                  </button>
                </div>
              </div>
            ))}
          </div>
        </>
      )}

      {/* FK Add/Edit Modal */}
      {fkModalOpen &&
        createPortal(
          <div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/50 backdrop-blur-sm">
            <div className="bg-white dark:bg-gray-800 rounded-2xl shadow-2xl w-full max-w-lg flex flex-col">
              {/* Modal Header */}
              <div className="flex items-center justify-between px-6 py-4 border-b border-gray-200 dark:border-gray-700">
                <h2 className="text-base font-bold text-gray-900 dark:text-white">
                  {editingFkId
                    ? translate('::App.SqlQueryManager.EditRelationship')
                    : translate('::App.SqlQueryManager.AddNewRelationship')}
                </h2>
                <button
                  onClick={() => setFkModalOpen(false)}
                  className="p-2 text-gray-400 hover:text-gray-600 rounded-lg transition-colors"
                >
                  <FaTimes className="w-4 h-4" />
                </button>
              </div>

              {/* Modal Body */}
              <div className="flex-1 overflow-y-auto px-6 py-4 space-y-4">
                {/* Relationship type */}
                <div>
                  <label className="block text-xs font-semibold text-gray-700 dark:text-gray-300 mb-2">
                    {translate('::App.SqlQueryManager.RelationshipType')}
                  </label>
                  <div className="flex gap-2">
                    {REL_TYPES.map((t) => (
                      <button
                        key={t.value}
                        type="button"
                        onClick={() => setFkForm((f) => ({ ...f, relationshipType: t.value }))}
                        className={`flex-1 py-2 px-3 rounded-lg border text-sm font-medium transition-all ${
                          fkForm.relationshipType === t.value
                            ? 'bg-indigo-600 border-indigo-600 text-white'
                            : 'bg-white dark:bg-gray-700 border-gray-200 dark:border-gray-600 text-gray-600 dark:text-gray-300 hover:border-indigo-300'
                        }`}
                      >
                        {t.label}
                        <span className="block text-xs opacity-70">{t.desc}</span>
                      </button>
                    ))}
                  </div>
                </div>

                {/* FK column / Referenced table & column */}
                <div className="grid grid-cols-2 gap-3">
                  <div>
                    <label className="block text-xs font-semibold text-gray-700 dark:text-gray-300 mb-1.5">
                      {translate('::App.SqlQueryManager.FkColumnInThisTable')}
                    </label>
                    <select
                      value={fkForm.fkColumnName}
                      onChange={(e) => setFkForm((f) => ({ ...f, fkColumnName: e.target.value }))}
                      className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg text-sm dark:bg-gray-700 dark:text-white focus:ring-2 focus:ring-indigo-500"
                    >
                      <option value="">
                        {translate('::App.Select')}
                      </option>
                      {columns
                        .filter((c) => c.columnName.trim())
                        .map((c) => (
                          <option key={c.id} value={c.columnName}>
                            {c.columnName}
                          </option>
                        ))}
                    </select>
                  </div>
                  <div>
                    <label className="block text-xs font-semibold text-gray-700 dark:text-gray-300 mb-1.5">
                      {translate('::App.SqlQueryManager.TargetTable')}
                    </label>
                    <select
                      value={fkForm.referencedTable}
                      onChange={(e) => {
                        const val = e.target.value
                        setFkForm((f) => ({ ...f, referencedTable: val, referencedColumn: '' }))
                        loadTargetColumns(val)
                      }}
                      className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg text-sm dark:bg-gray-700 dark:text-white focus:ring-2 focus:ring-indigo-500"
                    >
                      <option value="">
                        {translate('::App.Select')}
                      </option>
                      {dbTables.map((t) => (
                        <option key={`${t.schemaName}.${t.tableName}`} value={t.tableName}>
                          {t.tableName}
                        </option>
                      ))}
                    </select>
                  </div>
                </div>

                <div>
                  <label className="block text-xs font-semibold text-gray-700 dark:text-gray-300 mb-1.5">
                    {translate('::App.SqlQueryManager.TargetColumn')}
                    {targetColsLoading ? ` — ${translate('::App.SqlQueryManager.Loading')}` : ''}
                  </label>
                  <select
                    value={fkForm.referencedColumn}
                    onChange={(e) => setFkForm((f) => ({ ...f, referencedColumn: e.target.value }))}
                    disabled={targetColsLoading || targetTableColumns.length === 0}
                    className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg text-sm dark:bg-gray-700 dark:text-white focus:ring-2 focus:ring-indigo-500 disabled:opacity-60"
                  >
                    <option value="">
                      {translate('::App.SqlQueryManager.SelectTargetTableFirst')}
                    </option>
                    {targetTableColumns.map((col) => (
                      <option
                        key={col}
                        value={col}
                        disabled={!targetTableKeyColumns.some((k) => k.toLowerCase() === col.toLowerCase())}
                      >
                        {targetTableKeyColumns.some((k) => k.toLowerCase() === col.toLowerCase())
                          ? `${col} (PK/UNIQUE)`
                          : `${col} (Not Key)`}
                      </option>
                    ))}
                  </select>
                  {fkForm.referencedTable && !targetColsLoading && targetTableKeyColumns.length === 0 && (
                    <p className="mt-1 text-xs text-amber-600 dark:text-amber-400">
                      Seçilen tabloda FK için uygun PK/UNIQUE kolon bulunamadı.
                    </p>
                  )}
                </div>

                {/* Cascade */}
                <div className="grid grid-cols-2 gap-3">
                  <div>
                    <label className="block text-xs font-semibold text-gray-700 dark:text-gray-300 mb-1.5">
                      {translate('::App.SqlQueryManager.CascadeUpdate')}
                    </label>
                    <select
                      value={fkForm.cascadeUpdate}
                      onChange={(e) =>
                        setFkForm((f) => ({
                          ...f,
                          cascadeUpdate: e.target.value as CascadeBehavior,
                        }))
                      }
                      className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg text-sm dark:bg-gray-700 dark:text-white focus:ring-2 focus:ring-indigo-500"
                    >
                      {CASCADE_OPTIONS.map((o) => (
                        <option key={o.value} value={o.value}>
                          {o.label}
                        </option>
                      ))}
                    </select>
                  </div>
                  <div>
                    <label className="block text-xs font-semibold text-gray-700 dark:text-gray-300 mb-1.5">
                      {translate('::App.SqlQueryManager.CascadeDelete')}
                    </label>
                    <select
                      value={fkForm.cascadeDelete}
                      onChange={(e) =>
                        setFkForm((f) => ({
                          ...f,
                          cascadeDelete: e.target.value as CascadeBehavior,
                        }))
                      }
                      className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg text-sm dark:bg-gray-700 dark:text-white focus:ring-2 focus:ring-indigo-500"
                    >
                      {CASCADE_OPTIONS.map((o) => (
                        <option key={o.value} value={o.value}>
                          {o.label}
                        </option>
                      ))}
                    </select>
                  </div>
                </div>

                {/* Options */}
                <div className="flex items-center gap-6">
                  <label className="flex items-center gap-2 cursor-pointer">
                    <input
                      type="checkbox"
                      checked={fkForm.isRequired}
                      onChange={(e) => setFkForm((f) => ({ ...f, isRequired: e.target.checked }))}
                      className="w-4 h-4 text-indigo-600 rounded"
                    />
                    <span className="text-sm text-gray-700 dark:text-gray-300">
                      {translate('::App.SqlQueryManager.Required')}
                    </span>
                  </label>
                </div>

                <div>
                  <label className="block text-xs font-semibold text-gray-700 dark:text-gray-300 mb-1.5">
                    {translate('::App.SqlQueryManager.Description')}
                  </label>
                  <textarea
                    value={fkForm.description}
                    onChange={(e) => setFkForm((f) => ({ ...f, description: e.target.value }))}
                    rows={2}
                    placeholder={translate('::App.SqlQueryManager.OptionalDescriptionPlaceholder')}
                    className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg text-sm dark:bg-gray-700 dark:text-white focus:ring-2 focus:ring-indigo-500 resize-none"
                  />
                </div>
              </div>

              {/* Modal Footer */}
              <div className="flex items-center justify-end gap-2 px-6 py-4 border-t border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800/50 rounded-b-2xl">
                <button
                  onClick={() => setFkModalOpen(false)}
                  className="px-4 py-2 text-sm text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors"
                >
                  {translate('::Cancel')}
                </button>
                <button
                  onClick={saveFk}
                  disabled={
                    !fkForm.fkColumnName.trim() ||
                    !fkForm.referencedTable.trim() ||
                    !fkForm.referencedColumn.trim() ||
                    !targetTableKeyColumns.some(
                      (c) => c.toLowerCase() === fkForm.referencedColumn.trim().toLowerCase(),
                    )
                  }
                  className="px-4 py-2 text-sm bg-indigo-600 hover:bg-indigo-700 disabled:opacity-50 text-white rounded-lg transition-colors"
                >
                  {translate('::App.SqlQueryManager.Save')}
                </button>
              </div>
            </div>
          </div>,
          document.body,
        )}
    </div>
  )

  // ── Step 3: Index / Key ────────────────────────────────────────────────────

  const INDEX_TYPE_STYLES: Record<IndexType, { icon: string; badge: string }> = {
    PrimaryKey: {
      icon: 'bg-yellow-50 dark:bg-yellow-900/20 text-yellow-600 dark:text-yellow-400',
      badge: 'bg-yellow-100 dark:bg-yellow-900/30 text-yellow-700 dark:text-yellow-300',
    },
    UniqueKey: {
      icon: 'bg-green-50 dark:bg-green-900/20 text-green-600 dark:text-green-400',
      badge: 'bg-green-100 dark:bg-green-900/30 text-green-700 dark:text-green-300',
    },
    Index: {
      icon: 'bg-blue-50 dark:bg-blue-900/20 text-blue-600 dark:text-blue-400',
      badge: 'bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300',
    },
  }

  const renderIndexes = () => (
    <div className="space-y-3">
      {indexesLoading && (
        <div className="flex items-center justify-center py-10 text-gray-500 text-sm gap-2">
          <span className="animate-spin">&#9696;</span> {translate('::App.SqlQueryManager.Loading')}
        </div>
      )}
      {!indexesLoading && (
        <>
          {/* Header */}
          <div className="flex items-center justify-between">
            <span className="text-xs text-gray-500">
              {indexes.length === 0
                ? translate('::App.SqlQueryManager.NoIndexesDefined')
                : `${indexes.length} ${translate('::App.SqlQueryManager.IndexKey')}`}
            </span>
            <button
              onClick={openAddIndex}
              className="flex items-center gap-1 px-3 py-1.5 bg-indigo-600 hover:bg-indigo-700 text-white text-xs rounded-lg transition-colors"
            >
              <FaPlus className="w-2.5 h-2.5" /> {translate('::App.SqlQueryManager.AddIndexKey')}
            </button>
          </div>

          {/* Empty state */}
          {indexes.length === 0 && (
            <div className="py-8 text-center border-2 border-dashed border-gray-200 dark:border-gray-700 rounded-xl bg-gray-50 dark:bg-gray-800/50">
              <FaKey className="text-3xl mx-auto text-gray-300 dark:text-gray-600 mb-2" />
              <p className="text-sm text-gray-500">{translate('::App.SqlQueryManager.NoIndexesDefined')}</p>
              <p className="text-xs text-gray-400 mt-1">{translate('::App.SqlQueryManager.StepIsOptional')}</p>
            </div>
          )}

          {/* Index cards */}
          <div className="space-y-2 max-h-72 overflow-y-auto pr-1">
            {indexes.map((idx) => {
              const styles = INDEX_TYPE_STYLES[idx.indexType]
              return (
                <div
                  key={idx.id}
                  className="border border-slate-200 dark:border-gray-700 rounded-xl px-4 py-3 flex items-start gap-3 bg-white dark:bg-gray-800"
                >
                  <div className={`p-2 rounded-lg mt-0.5 flex-shrink-0 ${styles.icon}`}>
                    <FaKey className="w-3 h-3" />
                  </div>
                  <div className="flex-1 min-w-0">
                    <div className="flex items-center gap-2 flex-wrap">
                      <code className="text-sm font-semibold text-slate-900 dark:text-white">
                        [{idx.indexName}]
                      </code>
                      <span
                        className={`text-xs px-2 py-0.5 rounded-full font-medium ${styles.badge}`}
                      >
                        {idx.indexType}
                      </span>
                      <span className="text-xs text-gray-500">
                        {idx.isClustered ? 'CLUSTERED' : 'NONCLUSTERED'}
                      </span>
                    </div>
                    <div className="flex items-center gap-1 mt-1 flex-wrap">
                      {idx.columns.map((col, ci) => (
                        <span
                          key={ci}
                          className="text-xs bg-gray-100 dark:bg-gray-700 px-1.5 py-0.5 rounded font-mono"
                        >
                          {col.columnName} {col.order}
                        </span>
                      ))}
                    </div>
                    {idx.description && (
                      <p className="text-xs text-gray-400 mt-1 italic">{idx.description}</p>
                    )}
                  </div>
                  <div className="flex items-center gap-1 flex-shrink-0">
                    <button
                      onClick={() => openEditIndex(idx)}
                      title={translate('::App.SqlQueryManager.Edit')}
                      className="p-1.5 text-gray-400 hover:text-indigo-600 hover:bg-indigo-50 dark:hover:bg-indigo-900/20 rounded transition-colors"
                    >
                      <FaEdit className="w-3.5 h-3.5" />
                    </button>
                    <button
                      onClick={() => deleteIndex(idx.id)}
                      title={translate('::App.SqlQueryManager.Delete')}
                      className="p-1.5 text-gray-400 hover:text-red-600 hover:bg-red-50 dark:hover:bg-red-900/20 rounded transition-colors"
                    >
                      <FaTrash className="w-3.5 h-3.5" />
                    </button>
                  </div>
                </div>
              )
            })}
          </div>
        </>
      )}

      {/* Index Add/Edit Modal */}
      {indexModalOpen &&
        createPortal(
          <div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-black/50 backdrop-blur-sm">
            <div className="bg-white dark:bg-gray-800 rounded-2xl shadow-2xl w-full max-w-lg flex flex-col max-h-[90vh]">
              {/* Modal Header */}
              <div className="flex items-center justify-between px-6 py-4 border-b border-gray-200 dark:border-gray-700">
                <h2 className="text-base font-bold text-gray-900 dark:text-white">
                  {editingIndexId ? translate('::App.SqlQueryManager.EditIndexKey') : translate('::App.SqlQueryManager.AddNewIndexKey')}
                </h2>
                <button
                  onClick={() => setIndexModalOpen(false)}
                  className="p-2 text-gray-400 hover:text-gray-600 rounded-lg transition-colors"
                >
                  <FaTimes className="w-4 h-4" />
                </button>
              </div>

              {/* Modal Body */}
              <div className="flex-1 overflow-y-auto px-6 py-4 space-y-4">
                {/* Index Type */}
                <div>
                  <label className="block text-xs font-semibold text-gray-700 dark:text-gray-300 mb-2">
                    {translate('::App.SqlQueryManager.IndexKeyType')}
                  </label>
                  <div className="flex gap-2">
                    {INDEX_TYPES.map((t) => (
                      <button
                        key={t.value}
                        type="button"
                        onClick={() =>
                          setIndexForm((f) => ({
                            ...f,
                            indexType: t.value,
                            indexName: buildIndexName(t.value, f.columns),
                          }))
                        }
                        className={`flex-1 py-2 px-3 rounded-lg border text-sm font-medium transition-all ${
                          indexForm.indexType === t.value
                            ? 'bg-indigo-600 border-indigo-600 text-white'
                            : 'bg-white dark:bg-gray-700 border-gray-200 dark:border-gray-600 text-gray-600 dark:text-gray-300 hover:border-indigo-300'
                        }`}
                      >
                        {t.label}
                        <span className="block text-xs opacity-70">{translate('::' + t.desc)}</span>
                      </button>
                    ))}
                  </div>
                </div>

                {/* Index / Constraint Name */}
                <div>
                  <label className="block text-xs font-semibold text-gray-700 dark:text-gray-300 mb-1.5">
                    {translate('::App.SqlQueryManager.IndexConstraintName')}
                  </label>
                  <input
                    type="text"
                    value={indexForm.indexName}
                    onChange={(e) => setIndexForm((f) => ({ ...f, indexName: e.target.value }))}
                    placeholder={buildIndexName(indexForm.indexType, indexForm.columns) || `PK_EntityName_Id`}
                    className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg text-sm dark:bg-gray-700 dark:text-white focus:ring-2 focus:ring-indigo-500"
                  />
                </div>

                {/* Clustered */}
                <div className="flex items-center gap-3">
                  <label className="flex items-center gap-2 cursor-pointer">
                    <input
                      type="checkbox"
                      checked={indexForm.isClustered}
                      onChange={(e) =>
                        setIndexForm((f) => ({ ...f, isClustered: e.target.checked }))
                      }
                      className="w-4 h-4 text-indigo-600 rounded"
                    />
                    <span className="text-sm text-gray-700 dark:text-gray-300">Clustered</span>
                  </label>
                </div>

                {/* Column picker */}
                <div>
                  <label className="block text-xs font-semibold text-gray-700 dark:text-gray-300 mb-2">
                    {translate('::App.SqlQueryManager.Columns')}
                  </label>
                  <div className="border border-gray-200 dark:border-gray-600 rounded-lg overflow-hidden">
                    <div className="grid grid-cols-12 gap-2 px-3 py-1.5 bg-gray-50 dark:bg-gray-700 text-xs font-semibold text-gray-500">
                      <div className="col-span-1" />
                      <div className="col-span-7">{translate('::App.Listform.ListformField.Column')}</div>
                      <div className="col-span-4">{translate('::App.SqlQueryManager.SortOrder')}</div>
                    </div>
                    <div className="max-h-44 overflow-y-auto divide-y divide-gray-100 dark:divide-gray-700">
                      {columns
                        .filter((c) => c.columnName.trim())
                        .map((col) => {
                          const existing = indexForm.columns.find(
                            (ic) => ic.columnName === col.columnName,
                          )
                          return (
                            <div
                              key={col.id}
                              className="grid grid-cols-12 gap-2 px-3 py-1.5 items-center"
                            >
                              <div className="col-span-1">
                                <input
                                  type="checkbox"
                                  checked={!!existing}
                                  onChange={(e) => {
                                    if (e.target.checked) {
                                      setIndexForm((f) => {
                                        const newCols = [
                                          ...f.columns,
                                          { columnName: col.columnName, order: 'ASC' as const },
                                        ]
                                        return {
                                          ...f,
                                          columns: newCols,
                                          indexName: buildIndexName(f.indexType, newCols),
                                        }
                                      })
                                    } else {
                                      setIndexForm((f) => {
                                        const newCols = f.columns.filter(
                                          (ic) => ic.columnName !== col.columnName,
                                        )
                                        return {
                                          ...f,
                                          columns: newCols,
                                          indexName: buildIndexName(f.indexType, newCols),
                                        }
                                      })
                                    }
                                  }}
                                  className="w-4 h-4 text-indigo-600 rounded"
                                />
                              </div>
                              <div className="col-span-7 text-sm font-mono text-gray-800 dark:text-gray-200">
                                {col.columnName}
                              </div>
                              <div className="col-span-4">
                                {existing && (
                                  <select
                                    value={existing.order}
                                    onChange={(e) =>
                                      setIndexForm((f) => ({
                                        ...f,
                                        columns: f.columns.map((ic) =>
                                          ic.columnName === col.columnName
                                            ? { ...ic, order: e.target.value as 'ASC' | 'DESC' }
                                            : ic,
                                        ),
                                      }))
                                    }
                                    className="w-full px-2 py-0.5 text-xs border border-gray-300 dark:border-gray-600 rounded dark:bg-gray-700 dark:text-white"
                                  >
                                    <option value="ASC">ASC</option>
                                    <option value="DESC">DESC</option>
                                  </select>
                                )}
                              </div>
                            </div>
                          )
                        })}
                    </div>
                  </div>
                  {indexForm.columns.length > 0 && (
                    <p className="text-xs text-gray-400 mt-1">
                      {translate('::App.SqlQueryManager.Selected')}{' '}
                      {indexForm.columns.map((c) => `[${c.columnName}] ${c.order}`).join(', ')}
                    </p>
                  )}
                </div>

                <div>
                  <label className="block text-xs font-semibold text-gray-700 dark:text-gray-300 mb-1.5">
                    {translate('::App.SqlQueryManager.Description')}
                  </label>
                  <textarea
                    value={indexForm.description}
                    onChange={(e) =>
                      setIndexForm((f) => ({ ...f, description: e.target.value }))
                    }
                    rows={2}
                    placeholder={translate('::App.SqlQueryManager.OptionalDescriptionPlaceholder')}
                    className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg text-sm dark:bg-gray-700 dark:text-white focus:ring-2 focus:ring-indigo-500 resize-none"
                  />
                </div>
              </div>

              {/* Modal Footer */}
              <div className="flex items-center justify-end gap-2 px-6 py-4 border-t border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800/50 rounded-b-2xl">
                <button
                  onClick={() => setIndexModalOpen(false)}
                  className="px-4 py-2 text-sm text-gray-600 dark:text-gray-300 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors"
                >
                  {translate('::Cancel')}
                </button>
                <button
                  onClick={saveIndex}
                  disabled={!indexForm.indexName.trim() || indexForm.columns.length === 0}
                  className="px-4 py-2 text-sm bg-indigo-600 hover:bg-indigo-700 disabled:opacity-50 text-white rounded-lg transition-colors"
                >
                  {translate('::App.SqlQueryManager.Save')}
                </button>
              </div>
            </div>
          </div>,
          document.body,
        )}
    </div>
  )

  // ── Step 4: T-SQL Preview ──────────────────────────────────────────────────

  const renderSqlPreview = () => (
    <div className="flex flex-col gap-3">
      <div className="flex items-center justify-between">
        <p className="text-sm text-gray-600 dark:text-gray-400">
          {translate('::App.SqlQueryManager.GeneratedSqlDescription')}
        </p>
        <button
          className="text-xs text-blue-500 hover:underline"
          onClick={() => navigator.clipboard.writeText(generatedSql)}
        >
          {translate('::App.SqlQueryManager.Copy')}
        </button>
      </div>
      <pre className="bg-gray-900 text-green-300 rounded-lg p-4 text-xs overflow-auto max-h-96 leading-relaxed whitespace-pre">
        {generatedSql}
      </pre>
    </div>
  )

  // ── Render ─────────────────────────────────────────────────────────────────

  return (
    <Dialog isOpen={isOpen} onClose={handleClose} onRequestClose={handleClose} width={900}>
      <Dialog.Body className="flex flex-col gap-2">
        {/* Header */}
        <div className="flex items-center gap-3 border-b pb-3 flex-shrink-0">
          <FaTable className="text-2xl text-blue-500" />
          <div>
            <h5 className="font-bold">
              {isEditMode
                ? `${translate('::App.SqlQueryManager.EditTable')} — ${initialTableData?.tableName}`
                : translate('::App.SqlQueryManager.TableDesigner')}
            </h5>
            <p className="text-xs text-gray-500">
              {isEditMode
                ? translate('::App.SqlQueryManager.EditModeDescription')
                : translate('::App.SqlQueryManager.NewModeDescription')}
            </p>
          </div>
        </div>

        {/* Steps */}
        <div className="flex-shrink-0">{renderStepIndicator()}</div>

        {/* Content */}
        <StepContentWrapper>
          {step === 0 && renderColumnDesigner()}
          {step === 1 && renderEntitySettings()}
          {step === 2 && renderIndexes()}
          {step === 3 && renderRelationships()}
          {step === 4 && renderSqlPreview()}
        </StepContentWrapper>
      </Dialog.Body>

      <Dialog.Footer className="flex justify-between items-center border-t pt-3 mt-1">
        <Button variant="plain" onClick={handleClose}>
          {translate('::Cancel')}
        </Button>
        <div className="flex items-center gap-2">
          {step > 0 && (
            <Button variant="default" onClick={handleBack}>
              {translate('::Back')}
            </Button>
          )}
          {step < 4 ? (
            <Button variant="solid" color="blue-600" onClick={handleNext} disabled={!canGoNext()}>
              {translate('::App.SqlQueryManager.Next')}
            </Button>
          ) : (
            <Button
              variant="solid"
              color="green-600"
              icon={<FaCloudUploadAlt />}
              onClick={handleDeploy}
              loading={isDeploying}
              disabled={
                !dataSource ||
                isDeploying ||
                (isEditMode && generatedSql.includes('Henüz değişiklik yapılmadı'))
              }
            >
              {translate('::App.Platform.Deploy')}
            </Button>
          )}
        </div>
      </Dialog.Footer>
    </Dialog>
  )
}

export default SqlTableDesignerDialog
