<script setup lang="ts">
import { ref, computed, watch } from 'vue'
import type { ModelItem } from '@/types'

const props = defineProps<{
  modelValue: boolean
  models: ModelItem[]
  /** 当前已选模型 id，打开弹窗时用于初始化草稿与 Tab */
  currentModelId: string | number
}>()

const emit = defineEmits<{
  (e: 'update:modelValue', value: boolean): void
  (e: 'confirm', modelId: string | number): void
}>()

const activeModelTab = ref<'official' | 'mine'>('official')
const activeModelSeries = ref('')
const draftModelId = ref<string | number>('')
const modelSearchKeyword = ref('')

/** 根据模型名提取系列名（去掉参数量与日期后缀） */
function getModelSeries(name: string): string {
  return name
    .replace(/-\d+(?:\.\d+)?B.*$/i, '')
    .replace(/-\d+(?:\.\d+)?b.*$/i, '')
    .replace(/-\d{4}.*$/, '')
}

const dialogModels = computed(() => {
  const keyword = modelSearchKeyword.value.trim().toLowerCase()
  const tabModels = props.models.filter((model) => {
    if (activeModelTab.value === 'official') return model.model_source !== 'api'
    return model.model_source === 'api'
  })

  if (!keyword) return tabModels
  return tabModels.filter((model) => {
    return [model.name, model.description, model.path, model.online_model_name]
      .filter(Boolean)
      .some((text) => String(text).toLowerCase().includes(keyword))
  })
})

const modelSeriesGroups = computed(() => {
  const groupMap = new Map<string, ModelItem[]>()
  dialogModels.value.forEach((model) => {
    const series = getModelSeries(model.name)
    const list = groupMap.get(series) || []
    list.push(model)
    groupMap.set(series, list)
  })

  return Array.from(groupMap.entries()).map(([name, list]) => ({
    name,
    count: list.length,
    models: list,
  }))
})

const currentSeriesModels = computed(() => {
  return modelSeriesGroups.value.find((group) => group.name === activeModelSeries.value)?.models || []
})

const draftModel = computed(() => props.models.find((model) => model.id === draftModelId.value))

function syncActiveModelSeries() {
  const firstSeries = modelSeriesGroups.value[0]?.name || ''
  if (!activeModelSeries.value || !modelSeriesGroups.value.some((group) => group.name === activeModelSeries.value)) {
    activeModelSeries.value = firstSeries
  }
}

// 弹窗打开时初始化：草稿沿用当前选中、Tab 按来源切换、系列定位到草稿所在组
watch(
  () => props.modelValue,
  (visible) => {
    if (visible) {
      const current = props.models.find((model) => model.id === props.currentModelId)
      activeModelTab.value = current?.model_source === 'api' ? 'mine' : 'official'
      draftModelId.value = props.currentModelId
      syncActiveModelSeries()
    }
  },
)

watch([activeModelTab, modelSearchKeyword], () => {
  syncActiveModelSeries()
})

function chooseModelSeries(series: string) {
  activeModelSeries.value = series
}

function chooseDraftModel(model: ModelItem) {
  draftModelId.value = model.id
}

function handleCancel() {
  emit('update:modelValue', false)
}

function handleConfirm() {
  if (draftModelId.value !== '' && draftModelId.value !== undefined && draftModelId.value !== null) {
    emit('confirm', draftModelId.value)
  }
  emit('update:modelValue', false)
}
</script>

<template>
  <el-dialog
    :model-value="modelValue"
    class="model-select-dialog"
    width="860px"
    top="10vh"
    :show-close="false"
    append-to-body
    @update:model-value="emit('update:modelValue', $event)"
  >
    <template #header>
      <div class="model-dialog-header">
        <div class="model-dialog-title">
          <span>选择模型</span>
          <em>仅可选 1 个模型</em>
        </div>
        <button class="model-dialog-close" type="button" @click="handleCancel">
          <i class="fa fa-close" />
        </button>
      </div>
    </template>

    <div class="model-dialog-body">
      <div class="model-dialog-toolbar">
        <el-tabs v-model="activeModelTab" class="model-tabs">
          <el-tab-pane label="官方模型" name="official" />
          <el-tab-pane label="我的模型" name="mine" />
        </el-tabs>
        <el-input
          v-model="modelSearchKeyword"
          class="model-search"
          placeholder="从全部模型中搜索"
          clearable
        >
          <template #suffix>
            <i class="fa fa-search" />
          </template>
        </el-input>
      </div>

      <div class="model-dialog-content">
        <aside class="model-series-list">
          <div class="column-title">模型系列</div>
          <button
            v-for="series in modelSeriesGroups"
            :key="series.name"
            class="model-series-item"
            :class="{ active: activeModelSeries === series.name }"
            type="button"
            @click="chooseModelSeries(series.name)"
          >
            <i class="fa fa-star-o" />
            <span>{{ series.name }}</span>
            <em>{{ series.count }}</em>
          </button>
          <el-empty v-if="!modelSeriesGroups.length" description="暂无模型" :image-size="80" />
        </aside>

        <section class="model-version-list">
          <div class="column-title">快照版本</div>
          <button
            v-for="model in currentSeriesModels"
            :key="model.id"
            class="model-version-item"
            :class="{ active: draftModelId === model.id }"
            type="button"
            @click="chooseDraftModel(model)"
          >
            <div class="model-version-main">
              <strong>{{ model.name }}</strong>
              <span>{{ model.description || model.path || model.online_model_name || '暂无模型描述' }}</span>
            </div>
            <span class="model-radio-dot" />
          </button>
          <el-empty v-if="!currentSeriesModels.length" description="暂无快照版本" :image-size="80" />
        </section>
      </div>
    </div>

    <template #footer>
      <div class="model-dialog-footer">
        <div class="selected-model-summary">
          <span>已选 {{ draftModel ? 1 : 0 }}/1</span>
          <div v-if="draftModel" class="selected-model-pill">
            <i class="fa fa-star-o" />
            {{ draftModel.name }}
          </div>
        </div>
        <div class="model-dialog-actions">
          <el-button @click="handleCancel">取消</el-button>
          <el-button type="primary" @click="handleConfirm">确定</el-button>
        </div>
      </div>
    </template>
  </el-dialog>
</template>

<style scoped lang="scss">
:deep(.model-select-dialog) {
  max-width: calc(100vw - 48px);
  border-radius: 6px;
  box-shadow: 0 18px 46px rgba(15, 23, 42, 0.18);

  .el-dialog__header {
    padding: 0;
    margin: 0;
  }

  .el-dialog__body {
    padding: 0;
  }

  .el-dialog__footer {
    padding: 0;
  }
}

.model-dialog-header {
  height: 56px;
  padding: 0 20px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-bottom: 1px solid #eef0f5;
}

.model-dialog-title {
  display: flex;
  align-items: baseline;
  gap: 12px;

  span {
    font-size: 16px;
    font-weight: 700;
    color: #1f2937;
  }

  em {
    font-style: normal;
    font-size: 13px;
    color: #94a3b8;
  }
}

.model-dialog-close {
  width: 30px;
  height: 30px;
  border: 0;
  background: transparent;
  color: #64748b;
  cursor: pointer;
  font-size: 16px;
  border-radius: 6px;

  &:hover {
    background: #f5f6fb;
  }
}

.model-dialog-body {
  height: 452px;
}

.model-dialog-toolbar {
  height: 76px;
  padding: 14px 20px 0;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 18px;
  border-bottom: 1px solid #eef0f5;
}

.model-tabs {
  min-width: 210px;

  :deep(.el-tabs__item) {
    height: 42px;
    padding: 0 18px 0 0;
    font-size: 14px;
    font-weight: 600;
    color: #475569;
  }

  :deep(.el-tabs__active-bar) {
    height: 2px;
    background: #2563eb;
  }

  :deep(.el-tabs__nav-wrap::after) {
    display: none;
  }
}

.model-search {
  width: 280px;

  :deep(.el-input__wrapper) {
    border-radius: 6px;
    min-height: 36px;
  }
}

.model-dialog-content {
  display: grid;
  grid-template-columns: 280px 1fr;
  height: 376px;
  min-height: 0;
}

.model-series-list,
.model-version-list {
  padding: 16px 20px;
  overflow: auto;
}

.model-series-list {
  border-right: 1px solid #eef0f5;
}

.column-title {
  font-size: 13px;
  font-weight: 600;
  color: #64748b;
  margin-bottom: 12px;
}

.model-series-item,
.model-version-item {
  width: 100%;
  border: 1px solid #e5e7eb;
  background: #fff;
  border-radius: 6px;
  cursor: pointer;
  transition: all 0.2s;
  color: #1f2937;

  &:hover {
    border-color: #94a3b8;
    background: #f8fafc;
  }

  &.active {
    border-color: #2563eb;
    background: #eff6ff;
    box-shadow: inset 0 0 0 1px #2563eb;
  }
}

.model-series-item {
  height: 44px;
  padding: 0 12px;
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 10px;
  margin-bottom: 8px;
  text-align: left;

  i {
    color: #2563eb;
  }

  span {
    font-size: 14px;
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  em {
    font-style: normal;
    color: #777b92;
  }
}

.model-version-item {
  min-height: 64px;
  padding: 12px 14px;
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 14px;
  margin-bottom: 8px;
  text-align: left;
}

.model-version-main {
  display: grid;
  gap: 6px;
  min-width: 0;

  strong {
    color: #1f2937;
    font-size: 14px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  span {
    color: #64748b;
    font-size: 13px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}

.model-radio-dot {
  width: 16px;
  height: 16px;
  border: 1px solid #cbd5e1;
  border-radius: 50%;
  position: relative;
}

.model-version-item.active .model-radio-dot {
  border-color: #2563eb;

  &::after {
    content: '';
    position: absolute;
    inset: 3px;
    border-radius: 50%;
    background: #2563eb;
  }
}

.model-dialog-footer {
  height: 60px;
  padding: 0 20px;
  border-top: 1px solid #eef0f5;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.selected-model-summary {
  display: flex;
  align-items: center;
  gap: 10px;
  color: #475569;
  font-size: 13px;
}

.selected-model-pill {
  max-width: 300px;
  height: 28px;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 10px;
  border: 1px solid #dbeafe;
  border-radius: 4px;
  background: #eff6ff;
  color: #1f2937;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;

  i {
    color: #2563eb;
  }
}

.model-dialog-actions {
  display: flex;
  gap: 10px;
}

@media (max-width: 900px) {
  .model-dialog-toolbar,
  .model-dialog-footer {
    height: auto;
    align-items: flex-start;
    flex-direction: column;
    padding: 18px;
  }

  .model-search {
    width: 100%;
  }

  .model-dialog-content {
    grid-template-columns: 1fr;
  }

  .model-series-list {
    border-right: 0;
    border-bottom: 1px solid #eef0f5;
  }
}
</style>
