<script setup lang="ts">
import type { RemoteModelDescriptor, RemoteModelListData } from '#/api/ai/llm';

import { computed, onBeforeUnmount, ref } from 'vue';

import { EasyFlowFormModal } from '@easyflow/common-ui';

import { Check, Plus, Refresh, Search } from '@element-plus/icons-vue';
import {
  ElButton,
  ElEmpty,
  ElIcon,
  ElInput,
  ElMessage,
  ElSegmented,
  ElSkeleton,
  ElTag,
} from 'element-plus';

import { getRemoteModels, importRemoteModel } from '#/api/ai/llm';

type ModelTypeFilter =
  | 'allModel'
  | 'chatModel'
  | 'embeddingModel'
  | 'rerankModel';

const emit = defineEmits<{
  imported: [];
  manualAdd: [];
}>();

const visible = ref(false);
const providerId = ref('');
const providerName = ref('');
const models = ref<RemoteModelDescriptor[]>([]);
const loading = ref(false);
const errorMessage = ref('');
const truncated = ref(false);
const searchText = ref('');
const debouncedSearch = ref('');
const activeType = ref<ModelTypeFilter>('allModel');
const importingIds = ref(new Set<string>());
let searchTimer: ReturnType<typeof setTimeout> | undefined;
let requestSequence = 0;

const typeOptions = [
  { label: '全部', value: 'allModel' },
  { label: '对话', value: 'chatModel' },
  { label: '向量', value: 'embeddingModel' },
  { label: '重排', value: 'rerankModel' },
];

const typeLabelMap: Record<RemoteModelDescriptor['modelType'], string> = {
  chatModel: '对话',
  embeddingModel: '向量',
  rerankModel: '重排',
};

const getTypeLabel = (modelType: RemoteModelDescriptor['modelType']) =>
  typeLabelMap[modelType] || '对话';

const filteredModels = computed(() => {
  const keyword = debouncedSearch.value.trim().toLowerCase();
  return models.value
    .filter((model) => {
      const typeMatched =
        activeType.value === 'allModel' || model.modelType === activeType.value;
      if (!typeMatched || !keyword) {
        return typeMatched;
      }
      return model.modelId.toLowerCase().includes(keyword);
    })
    .sort((left, right) =>
      left.modelId.localeCompare(right.modelId, undefined, {
        sensitivity: 'base',
      }),
    );
});

const hasFilters = computed(
  () => Boolean(searchText.value.trim()) || activeType.value !== 'allModel',
);

const emptyDescription = computed(() =>
  hasFilters.value ? '没有匹配的模型' : '远端没有返回可添加的模型',
);

const dialogTitle = computed(() =>
  providerName.value ? `${providerName.value} 模型` : '获取模型列表',
);

const handleSearchInput = () => {
  if (searchTimer) {
    clearTimeout(searchTimer);
  }
  searchTimer = setTimeout(() => {
    debouncedSearch.value = searchText.value;
  }, 160);
};

const clearFilters = () => {
  searchText.value = '';
  debouncedSearch.value = '';
  activeType.value = 'allModel';
};

const requestModels = async () => {
  if (!providerId.value || loading.value) {
    return;
  }
  const sequence = ++requestSequence;
  loading.value = true;
  errorMessage.value = '';

  try {
    const response = await getRemoteModels(providerId.value);
    if (sequence !== requestSequence) {
      return;
    }
    if (response?.errorCode !== 0) {
      throw new Error(response?.message || '获取模型列表失败');
    }
    const data = (response.data || {}) as RemoteModelListData;
    models.value = Array.isArray(data.models) ? data.models : [];
    truncated.value = Boolean(data.truncated);
  } catch (error: any) {
    if (sequence === requestSequence) {
      models.value = [];
      truncated.value = false;
      errorMessage.value =
        error?.response?.data?.message || error?.message || '获取模型列表失败';
    }
  } finally {
    if (sequence === requestSequence) {
      loading.value = false;
    }
  }
};

const handleImport = async (model: RemoteModelDescriptor) => {
  if (model.added || !model.addable || importingIds.value.has(model.modelId)) {
    return;
  }

  importingIds.value = new Set(importingIds.value).add(model.modelId);
  try {
    const response = await importRemoteModel(providerId.value, model.modelId);
    if (response?.errorCode !== 0) {
      throw new Error(response?.message || '添加模型失败');
    }
    models.value = models.value.map((item) =>
      item.modelId === model.modelId ? { ...item, added: true } : item,
    );
    ElMessage.success(
      response.data?.status === 'ALREADY_EXISTS' ? '模型已添加' : '添加成功',
    );
    emit('imported');
  } catch (error: any) {
    ElMessage.error(
      error?.response?.data?.message || error?.message || '添加模型失败',
    );
  } finally {
    const nextIds = new Set(importingIds.value);
    nextIds.delete(model.modelId);
    importingIds.value = nextIds;
  }
};

const handleManualAdd = () => {
  visible.value = false;
  emit('manualAdd');
};

const handleOpenChange = (open: boolean) => {
  visible.value = open;
  if (!open) {
    requestSequence += 1;
  }
};

const openDialog = (nextProviderId: string, nextProviderName = '') => {
  providerId.value = nextProviderId;
  providerName.value = nextProviderName;
  models.value = [];
  importingIds.value = new Set();
  errorMessage.value = '';
  truncated.value = false;
  clearFilters();
  visible.value = true;
  void requestModels();
};

onBeforeUnmount(() => {
  if (searchTimer) {
    clearTimeout(searchTimer);
  }
  requestSequence += 1;
});

defineExpose({ openDialog });
</script>

<template>
  <EasyFlowFormModal
    :open="visible"
    :title="dialogTitle"
    width="800px"
    :show-footer="false"
    @update:open="handleOpenChange"
  >
    <div class="remote-model-dialog">
      <div class="remote-model-dialog__toolbar">
        <ElInput
          v-model="searchText"
          clearable
          :disabled="loading || Boolean(errorMessage)"
          placeholder="搜索模型 ID"
          aria-label="搜索远端模型"
          @input="handleSearchInput"
          @clear="handleSearchInput"
        >
          <template #prefix>
            <ElIcon><Search /></ElIcon>
          </template>
        </ElInput>
        <ElButton
          :icon="Refresh"
          :loading="loading"
          :disabled="loading"
          aria-label="刷新远端模型列表"
          @click="requestModels"
        >
          刷新
        </ElButton>
      </div>

      <div class="remote-model-dialog__filters">
        <ElSegmented
          v-model="activeType"
          :options="typeOptions"
          aria-label="按模型类型筛选"
        />
        <span
          v-if="!loading && !errorMessage"
          class="remote-model-dialog__count"
        >
          {{ filteredModels.length }} 个模型
        </span>
      </div>

      <div
        v-if="loading"
        class="remote-model-dialog__loading"
        aria-live="polite"
      >
        <ElSkeleton v-for="item in 5" :key="item" animated :rows="1" />
      </div>

      <div v-else-if="errorMessage" class="remote-model-dialog__state">
        <strong>获取失败</strong>
        <p>{{ errorMessage }}</p>
        <div class="remote-model-dialog__state-actions">
          <ElButton type="primary" :icon="Refresh" @click="requestModels">
            重新获取
          </ElButton>
          <ElButton @click="handleManualAdd">手动新增</ElButton>
        </div>
      </div>

      <div
        v-else-if="filteredModels.length === 0"
        class="remote-model-dialog__state"
      >
        <ElEmpty :description="emptyDescription">
          <ElButton v-if="hasFilters" @click="clearFilters">清空筛选</ElButton>
          <ElButton v-else :icon="Refresh" @click="requestModels">
            重新获取
          </ElButton>
        </ElEmpty>
      </div>

      <div v-else class="remote-model-dialog__list">
        <div
          v-for="model in filteredModels"
          :key="model.modelId"
          class="remote-model-row"
        >
          <div class="remote-model-row__identity">
            <strong :title="model.modelId">
              {{ model.modelId }}
            </strong>
          </div>
          <div class="remote-model-row__abilities">
            <ElTag size="small" effect="plain">
              {{ getTypeLabel(model.modelType) }}
            </ElTag>
            <ElTag
              v-if="model.supportImage"
              size="small"
              effect="plain"
              type="success"
            >
              视觉
            </ElTag>
            <ElTag
              v-if="model.supportThinking"
              size="small"
              effect="plain"
              type="info"
            >
              推理
            </ElTag>
            <ElTag
              v-if="model.supportTool"
              size="small"
              effect="plain"
              type="warning"
            >
              工具
            </ElTag>
          </div>
          <div class="remote-model-row__action">
            <span v-if="model.added" class="remote-model-row__added">
              <ElIcon><Check /></ElIcon>
              已添加
            </span>
            <ElButton
              v-else
              circle
              text
              :icon="Plus"
              :loading="importingIds.has(model.modelId)"
              :disabled="!model.addable || importingIds.has(model.modelId)"
              :title="model.unavailableReason || '添加模型'"
              :aria-label="`添加 ${model.modelId}`"
              @click="handleImport(model)"
            />
          </div>
        </div>
      </div>

      <p v-if="truncated" class="remote-model-dialog__notice">
        模型数量较多，当前显示前 1000 项。
      </p>
    </div>
  </EasyFlowFormModal>
</template>

<style scoped>
.remote-model-dialog {
  display: flex;
  flex-direction: column;
  gap: 16px;
  min-height: 0;
}

.remote-model-dialog__toolbar {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 8px;
}

.remote-model-dialog__filters {
  display: flex;
  gap: 16px;
  align-items: center;
  justify-content: space-between;
}

.remote-model-dialog__count,
.remote-model-dialog__notice {
  font-size: 12px;
  color: hsl(var(--text-muted));
}

.remote-model-dialog__loading {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding-top: 16px;
}

.remote-model-dialog__state {
  display: flex;
  flex: 1;
  flex-direction: column;
  gap: 8px;
  align-items: center;
  justify-content: center;
  min-height: 280px;
  text-align: center;
}

.remote-model-dialog__state strong {
  color: hsl(var(--text-strong));
}

.remote-model-dialog__state p {
  max-width: 560px;
  margin: 0;
  font-size: 13px;
  line-height: 1.6;
  color: hsl(var(--text-muted));
}

.remote-model-dialog__state-actions {
  display: flex;
  gap: 8px;
  margin-top: 8px;
}

.remote-model-dialog__list {
  overflow: hidden;
}

.remote-model-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(160px, auto) 64px;
  gap: 16px;
  align-items: center;
  min-height: 64px;
  padding: 0 12px;
  border-bottom: 1px solid hsl(var(--divider-faint) / 42%);
  transition: background-color 140ms ease;
}

.remote-model-row:hover {
  background: hsl(var(--surface-contrast-soft) / 28%);
}

.remote-model-row__identity {
  min-width: 0;
}

.remote-model-row__identity strong {
  display: block;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 14px;
  font-weight: 600;
  color: hsl(var(--text-strong));
}

.remote-model-row__abilities {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  justify-content: flex-end;
}

.remote-model-row__action {
  display: flex;
  justify-content: flex-end;
}

.remote-model-row__added {
  display: inline-flex;
  gap: 4px;
  align-items: center;
  font-size: 12px;
  color: hsl(var(--success));
}

.remote-model-dialog__notice {
  margin: -8px 0 0;
}

@media (max-width: 768px) {
  .remote-model-dialog {
    min-height: 0;
  }

  .remote-model-dialog__toolbar {
    grid-template-columns: minmax(0, 1fr);
  }

  .remote-model-dialog__filters {
    align-items: flex-start;
    flex-direction: column;
    gap: 8px;
  }

  .remote-model-row {
    grid-template-columns: minmax(0, 1fr) auto;
    gap: 8px;
  }

  .remote-model-row__abilities {
    display: none;
  }
}
</style>
