<script setup>
import { ref, computed, watch } from 'vue'
import { NIcon, NSpin, NInput, NModal, NInputNumber, NButton, useMessage } from 'naive-ui'
import {
  ServerOutline, GridOutline, RefreshOutline, ChevronForwardOutline, EyeOutline
} from '@vicons/ionicons5'
import { getTables, getTableColumns, getTableRowCount, getTableData } from '../../api/datasource'
import QueryResult from './QueryResult.vue'

const props = defineProps({
  datasourceId: { type: [Number, null], default: null }
})
const emit = defineEmits(['insert-table', 'insert-column'])

const message = useMessage()
const loading = ref(false)
const schemaFilter = ref('')
const tableFilter = ref('')
const tables = ref([])
const expandedTable = ref(null)
const columns = ref([])
const tableCountMap = ref({})
const loadingTable = ref(null)

const showDataPreview = ref(false)
const previewTable = ref('')
const previewLimit = ref(100)
const previewResult = ref(null)
const previewLoading = ref(false)

async function loadTables() {
  if (!props.datasourceId) return
  loading.value = true
  try {
    const res = await getTables(props.datasourceId, schemaFilter.value || null)
    tables.value = res.data || []
  } catch (e) {
    message.error('加载表失败：' + e.message)
  } finally {
    loading.value = false
  }
}

async function toggleTable(table) {
  if (expandedTable.value === table) {
    expandedTable.value = null
    columns.value = []
    return
  }
  expandedTable.value = table
  loadingTable.value = table
  try {
    const [cols, count] = await Promise.all([
      getTableColumns(props.datasourceId, table, schemaFilter.value || null),
      getTableRowCount(props.datasourceId, table, schemaFilter.value || null)
    ])
    columns.value = cols.data || []
    tableCountMap.value[table] = count.data || 0
  } catch (e) {
    columns.value = []
    message.error('加载字段失败：' + e.message)
  } finally {
    loadingTable.value = null
  }
}

function insertTable(name) {
  emit('insert-table', name)
}

function insertColumn(name) {
  emit('insert-column', name)
}

async function openDataPreview(table) {
  previewTable.value = table
  previewLimit.value = 100
  previewResult.value = null
  showDataPreview.value = true
  await loadDataPreview()
}

async function loadDataPreview() {
  if (!props.datasourceId || !previewTable.value) return
  previewLoading.value = true
  try {
    const res = await getTableData(
      props.datasourceId,
      previewTable.value,
      schemaFilter.value || null,
      previewLimit.value
    )
    previewResult.value = res.data || null
  } catch (e) {
    previewResult.value = null
    message.error('加载表数据失败：' + e.message)
  } finally {
    previewLoading.value = false
  }
}

const filteredTables = computed(() => {
  if (!tableFilter.value) return tables.value
  const kw = tableFilter.value.toLowerCase()
  return tables.value.filter(t => t.name.toLowerCase().includes(kw))
})

watch(() => props.datasourceId, () => {
  expandedTable.value = null
  columns.value = []
  tableCountMap.value = {}
  if (props.datasourceId) loadTables()
}, { immediate: true })
</script>

<template>
  <div class="table-explorer">
    <div class="explorer-header">
      <span class="header-title">
        <n-icon size="14"><ServerOutline /></n-icon>
        表结构
      </span>
      <button class="icon-btn-sm" @click="loadTables" :disabled="!datasourceId" title="刷新">
        <n-icon size="12"><RefreshOutline /></n-icon>
      </button>
    </div>

    <div class="filter-row">
      <n-input
        v-model:value="schemaFilter"
        size="tiny"
        placeholder="schema"
        @blur="loadTables"
        @keyup.enter="loadTables"
      />
      <n-input
        v-model:value="tableFilter"
        size="tiny"
        placeholder="过滤表名"
      />
    </div>

    <div class="explorer-body">
      <div v-if="loading" class="loading"><n-spin size="small" /></div>
      <div v-else-if="!datasourceId" class="empty-text">未选择数据源</div>
      <div v-else-if="!filteredTables.length" class="empty-text">无表</div>
      <div v-else class="table-list">
        <div
          v-for="t in filteredTables"
          :key="t.name"
          class="table-node"
        >
          <div
            class="table-row"
            :class="{ expanded: expandedTable === t.name }"
            @click="toggleTable(t.name)"
          >
            <n-icon size="12" class="expand-icon" :class="{ rotated: expandedTable === t.name }">
              <ChevronForwardOutline />
            </n-icon>
            <n-icon size="12" color="var(--color-accent)"><GridOutline /></n-icon>
            <span class="table-name" :title="t.name" @dblclick.stop="insertTable(t.name)">{{ t.name }}</span>
            <span class="table-type">{{ t.type }}</span>
            <n-button
              quaternary
              size="tiny"
              class="action-btn"
              title="查看数据"
              @click.stop="openDataPreview(t.name)"
            >
              <template #icon>
                <n-icon size="12"><EyeOutline /></n-icon>
              </template>
            </n-button>
          </div>

          <div v-if="expandedTable === t.name" class="column-list">
            <div v-if="loadingTable === t.name" class="loading"><n-spin size="small" /></div>
            <template v-else>
              <div class="table-meta">
                <span class="meta-item" v-if="tableCountMap[t.name] !== undefined">
                  约 {{ tableCountMap[t.name].toLocaleString() }} 行
                </span>
                <span class="meta-item">{{ columns.length }} 列</span>
              </div>
              <div
                v-for="col in columns"
                :key="col.name"
                class="column-row"
                @dblclick="insertColumn(col.name)"
                :title="'双击插入字段名'"
              >
                <span class="col-name">{{ col.name }}</span>
                <span class="col-type">{{ col.type }}<template v-if="col.size">({{ col.size }})</template></span>
                <span class="col-null" :class="{ 'is-null': col.nullable }">
                  {{ col.nullable ? 'NULL' : 'NOT NULL' }}
                </span>
              </div>
            </template>
          </div>
        </div>
      </div>
    </div>

    <n-modal
      v-model:show="showDataPreview"
      preset="card"
      :title="`预览数据：${previewTable}`"
      style="width: 80vw; max-width: 1200px;"
      :mask-closable="false"
    >
      <div class="preview-toolbar">
        <span class="toolbar-label">行数限制</span>
        <n-input-number
          v-model:value="previewLimit"
          :min="1"
          :max="1000"
          size="small"
          style="width: 120px"
          @update:value="loadDataPreview"
        />
        <n-button size="small" @click="loadDataPreview">刷新</n-button>
      </div>
      <div class="preview-body">
        <query-result :result="previewResult" :loading="previewLoading" />
      </div>
    </n-modal>
  </div>
</template>

<style scoped>
.table-explorer {
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 0;
}
.explorer-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 8px 12px;
  border-bottom: 1px solid var(--border-color);
  background: var(--bg-card);
}
.header-title {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-secondary);
}
.icon-btn-sm {
  background: none; border: none;
  color: var(--text-muted); cursor: pointer;
  padding: 4px; border-radius: 4px;
  display: flex; align-items: center;
}
.icon-btn-sm:hover { color: var(--color-accent); background: rgba(37,99,235,0.1); }
.icon-btn-sm:disabled { opacity: 0.4; cursor: not-allowed; }

.filter-row {
  display: flex; gap: 4px; padding: 6px 12px;
  border-bottom: 1px solid var(--border-color);
  background: var(--bg-card);
}

.explorer-body { flex: 1; overflow-y: auto; }
.loading, .empty-text {
  display: flex; align-items: center; justify-content: center;
  padding: 24px; color: var(--text-muted); font-size: 12px;
}

.table-list { padding: 4px 0; }
.table-node { display: flex; flex-direction: column; }
.table-row {
  display: flex; align-items: center; gap: 4px;
  padding: 5px 12px;
  cursor: pointer;
  transition: all 0.15s;
  font-size: 12px;
  color: var(--text-secondary);
}
.table-row:hover { background: rgba(37,99,235,0.06); }
.table-row.expanded { background: rgba(37,99,235,0.08); color: var(--color-accent); }
.expand-icon { transition: transform 0.15s; color: var(--text-muted); }
.expand-icon.rotated { transform: rotate(90deg); }
.table-name {
  flex: 1; min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.table-type {
  font-size: 10px; color: var(--text-muted);
  background: rgba(100,116,139,0.1); padding: 1px 4px; border-radius: 3px;
}
.action-btn { opacity: 0.6; transition: opacity 0.15s; }
.table-row:hover .action-btn { opacity: 1; }

.column-list {
  border-left: 1px solid var(--border-color);
  margin-left: 28px;
  background: var(--bg-secondary);
}
.table-meta {
  display: flex; gap: 8px;
  padding: 4px 8px;
  font-size: 10px; color: var(--text-muted);
  border-bottom: 1px dashed var(--border-color);
}
.column-row {
  display: flex; align-items: center; gap: 6px;
  padding: 3px 8px;
  font-size: 11px;
  color: var(--text-secondary);
  cursor: pointer;
}
.column-row:hover { background: rgba(37,99,235,0.06); }
.col-name {
  flex: 1; min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  font-family: 'JetBrains Mono', 'Consolas', monospace;
}
.col-type {
  color: var(--color-accent);
  font-size: 10px;
  font-family: monospace;
}
.col-null {
  font-size: 9px; padding: 1px 4px;
  border-radius: 2px;
}
.col-null.is-null { color: var(--text-muted); background: rgba(100,116,139,0.1); }
.col-null:not(.is-null) { color: #f59e0b; background: rgba(245,158,11,0.1); }

.preview-toolbar {
  display: flex; align-items: center; gap: 12px;
  padding-bottom: 12px;
  margin-bottom: 12px;
  border-bottom: 1px solid var(--border-color);
}
.toolbar-label {
  font-size: 12px;
  color: var(--text-secondary);
}
.preview-body {
  height: 60vh;
  min-height: 300px;
}
</style>
