<script setup lang="ts">
import type { ModelAbilityItem } from '#/views/ai/model/modelUtils/model-ability';

import { computed, reactive, ref, watch } from 'vue';

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

import {
  ArrowDown,
  ArrowUp,
  InfoFilled,
  Loading,
} from '@element-plus/icons-vue';
import {
  ElForm,
  ElFormItem,
  ElIcon,
  ElInput,
  ElMessage,
  ElOption,
  ElSelect,
  ElTooltip,
} from 'element-plus';

import { resolveModelCapabilities } from '#/api/ai/llm';
import { api } from '#/api/request';
import { $t } from '#/locales';
import {
  getDefaultModelAbility,
  handleTagClick as handleTagClickUtil,
  syncTagSelectedStatus as syncTagSelectedStatusUtil,
} from '#/views/ai/model/modelUtils/model-ability';
import { resetModelAbility } from '#/views/ai/model/modelUtils/model-ability-utils';

type AgentHttpVersionPolicy = 'AUTO' | 'HTTP_1_1' | 'HTTP_2_PREFERRED';
type AgentSystemContentFormat = 'STRING' | 'TEXT_PARTS';

interface ModelOptions {
  agentHttpVersionPolicy: AgentHttpVersionPolicy;
  agentSystemContentFormat: AgentSystemContentFormat;
  [key: string]: unknown;
}

interface FormData {
  id?: string;
  modelType: string;
  title: string;
  modelName: string;
  groupName: string;
  providerId: string;
  invokeCode: string;
  publishEnabled: boolean;
  apiKey: string;
  endpoint: string;
  requestPath: string;
  supportThinking: boolean | null;
  supportTool: boolean | null;
  supportImage: boolean | null;
  supportAudio: boolean;
  supportFree: boolean;
  supportVideo: boolean;
  supportImageB64Only: boolean;
  supportToolMessage: boolean | null;
  options: ModelOptions;
}

const props = defineProps({
  providerId: {
    type: String,
    default: '',
  },
});

const emit = defineEmits(['reload']);
const selectedProviderId = ref<string>(props.providerId ?? '');

watch(
  () => props.providerId,
  (newVal) => {
    if (newVal) {
      selectedProviderId.value = newVal;
    }
  },
  { immediate: true },
);

const formDataRef = ref();
const isAdd = ref(true);
const dialogVisible = ref(false);
const btnLoading = ref(false);
const showAdvanced = ref(false);
const capabilityLoading = ref(false);
const autoDetectedModelType = ref(false);
let capabilityRequestSequence = 0;
let manuallyEditedModelName = '';

const formData = reactive<FormData>({
  modelType: '',
  title: '',
  modelName: '',
  groupName: '',
  providerId: '',
  invokeCode: '',
  publishEnabled: false,
  apiKey: '',
  endpoint: '',
  requestPath: '',
  supportThinking: null,
  supportTool: null,
  supportImage: null,
  supportAudio: false,
  supportFree: false,
  supportVideo: false,
  supportImageB64Only: false,
  supportToolMessage: null,
  options: {
    agentHttpVersionPolicy: 'AUTO',
    agentSystemContentFormat: 'STRING',
  },
});

const agentHttpVersionOptions = [
  { label: '自动', value: 'AUTO' },
  { label: 'HTTP/1.1 兼容', value: 'HTTP_1_1' },
  { label: 'HTTP/2 优先', value: 'HTTP_2_PREFERRED' },
] as const;

const agentSystemContentFormatOptions = [
  { label: '字符串（默认）', value: 'STRING' },
  { label: '内容块数组', value: 'TEXT_PARTS' },
] as const;

const normalizeAgentHttpVersionPolicy = (
  value?: unknown,
): AgentHttpVersionPolicy => {
  if (value === 'HTTP_1_1' || value === 'HTTP_2_PREFERRED') {
    return value;
  }
  return 'AUTO';
};

const normalizeAgentSystemContentFormat = (
  value?: unknown,
): AgentSystemContentFormat => {
  return value === 'TEXT_PARTS' ? 'TEXT_PARTS' : 'STRING';
};

const normalizeModelOptions = (options?: unknown): ModelOptions => {
  const source =
    options && typeof options === 'object' && !Array.isArray(options)
      ? (options as Record<string, unknown>)
      : {};
  return {
    ...source,
    agentHttpVersionPolicy: normalizeAgentHttpVersionPolicy(
      source.agentHttpVersionPolicy,
    ),
    agentSystemContentFormat: normalizeAgentSystemContentFormat(
      source.agentSystemContentFormat,
    ),
  };
};

const modelAbility = ref<ModelAbilityItem[]>(getDefaultModelAbility());
const visibleModelAbility = computed(() => modelAbility.value);
type SelectableModelType = '' | 'embeddingModel' | 'rerankModel';

const selectedModelType = ref<SelectableModelType>('');
const modelTypeAbilityOptions = [
  {
    label: $t('llmProvider.embeddingModel'),
    value: 'embeddingModel',
  },
  {
    label: $t('llmProvider.rerankModel'),
    value: 'rerankModel',
  },
] as const;
const hasSpecialModelType = computed(() => Boolean(selectedModelType.value));
const abilityIconMap: Record<string, string> = {
  embeddingModel: 'svg:knowledge',
  rerankModel: 'svg:data-center',
  thinking: 'svg:llm',
  tool: 'svg:wrench',
  image: 'mdi:image-outline',
};

const syncTagSelectedStatus = () => {
  syncTagSelectedStatusUtil(modelAbility.value, formData);
};

const resetAbilitySelection = () => {
  resetModelAbility(modelAbility.value);
  formData.supportThinking = false;
  formData.supportTool = false;
  formData.supportImage = false;
  formData.supportToolMessage = false;
  syncTagSelectedStatus();
};

const markCapabilitiesAsManuallyEdited = () => {
  manuallyEditedModelName = formData.modelName.trim();
  capabilityRequestSequence += 1;
  capabilityLoading.value = false;
};

const handleAbilityChipClick = (item: ModelAbilityItem) => {
  if (hasSpecialModelType.value) {
    return;
  }
  markCapabilitiesAsManuallyEdited();
  handleTagClickUtil(item, formData);
  if (item.field === 'supportTool') {
    formData.supportToolMessage = formData.supportTool;
  }
};

const handleModelNameInput = () => {
  manuallyEditedModelName = '';
  capabilityRequestSequence += 1;
  capabilityLoading.value = false;
  autoDetectedModelType.value = false;
  selectedModelType.value = '';
  formData.supportThinking = null;
  formData.supportTool = null;
  formData.supportImage = null;
  formData.supportToolMessage = null;
  syncTagSelectedStatus();
};

const handleModelTypeChipClick = (
  modelType: Exclude<SelectableModelType, ''>,
) => {
  const nextType = selectedModelType.value === modelType ? '' : modelType;
  markCapabilitiesAsManuallyEdited();
  autoDetectedModelType.value = false;
  selectedModelType.value = nextType;
  if (nextType) {
    resetAbilitySelection();
  } else {
    formData.supportThinking = null;
    formData.supportTool = null;
    formData.supportImage = null;
    formData.supportToolMessage = null;
    syncTagSelectedStatus();
  }
};

const getAbilityIcon = (value: string) => abilityIconMap[value] || 'svg:llm';

const resolveModelType = (): FormData['modelType'] => {
  return selectedModelType.value || 'chatModel';
};

const normalizeSelectableModelType = (
  modelType?: string,
): SelectableModelType => {
  return modelType === 'embeddingModel' || modelType === 'rerankModel'
    ? modelType
    : '';
};

const resetFormData = () => {
  Object.assign(formData, {
    id: '',
    modelType: '',
    title: '',
    modelName: '',
    groupName: '',
    providerId: '',
    invokeCode: '',
    publishEnabled: false,
    apiKey: '',
    endpoint: '',
    requestPath: '',
    supportThinking: null,
    supportTool: null,
    supportAudio: false,
    supportVideo: false,
    supportImage: null,
    supportImageB64Only: false,
    supportFree: false,
    supportToolMessage: null,
    options: normalizeModelOptions(),
  });
};

defineExpose({
  openAddDialog(modelType?: string) {
    isAdd.value = true;
    formDataRef.value?.resetFields();
    resetFormData();
    showAdvanced.value = false;
    autoDetectedModelType.value = false;
    manuallyEditedModelName = '';
    selectedModelType.value = normalizeSelectableModelType(modelType);
    if (selectedModelType.value) {
      resetAbilitySelection();
    } else {
      syncTagSelectedStatus();
    }
    dialogVisible.value = true;
  },

  openEditDialog(item: any) {
    dialogVisible.value = true;
    isAdd.value = false;
    resetFormData();
    showAdvanced.value = false;
    autoDetectedModelType.value = false;
    manuallyEditedModelName = '';
    Object.assign(formData, {
      id: item.id,
      modelType: item.modelType || '',
      title: item.title || '',
      modelName: item.modelName || '',
      groupName: item.groupName || '',
      providerId: item.providerId || '',
      invokeCode: item.invokeCode || '',
      publishEnabled: item.publishEnabled || false,
      endpoint: item.endpoint || '',
      requestPath: item.requestPath || '',
      apiKey: item.apiKey || '',
      supportThinking: item.supportThinking ?? null,
      supportAudio: item.supportAudio || false,
      supportImage: item.supportImage ?? null,
      supportImageB64Only: item.supportImageB64Only || false,
      supportVideo: item.supportVideo || false,
      supportTool: item.supportTool ?? null,
      supportFree: item.supportFree || false,
      supportToolMessage: item.supportToolMessage ?? null,
      options: normalizeModelOptions(item.options),
    });
    selectedModelType.value = normalizeSelectableModelType(item.modelType);
    if (selectedModelType.value) {
      resetAbilitySelection();
    } else {
      syncTagSelectedStatus();
    }
  },
});

const closeDialog = () => {
  capabilityRequestSequence += 1;
  dialogVisible.value = false;
};

const detectModelCapabilities = async () => {
  const modelName = formData.modelName.trim();
  if (!modelName || manuallyEditedModelName === modelName) {
    return;
  }

  const requestSequence = ++capabilityRequestSequence;
  capabilityLoading.value = true;
  try {
    const providerId = isAdd.value
      ? selectedProviderId.value
      : formData.providerId;
    const res = await resolveModelCapabilities({ modelName, providerId });
    if (
      requestSequence !== capabilityRequestSequence ||
      res.errorCode !== 0 ||
      !res.data
    ) {
      return;
    }

    const capability = res.data;
    manuallyEditedModelName = '';
    if (!capability.detected) {
      if (autoDetectedModelType.value) {
        selectedModelType.value = '';
      }
      autoDetectedModelType.value = false;
      formData.supportThinking = null;
      formData.supportTool = null;
      formData.supportImage = null;
      formData.supportToolMessage = null;
      syncTagSelectedStatus();
      return;
    }

    autoDetectedModelType.value = true;
    formData.modelType = capability.modelType;
    selectedModelType.value = normalizeSelectableModelType(
      capability.modelType,
    );
    formData.supportThinking = capability.supportThinking ?? null;
    formData.supportTool = capability.supportTool ?? null;
    formData.supportImage = capability.supportImage ?? null;
    formData.supportToolMessage = capability.supportTool ?? null;
    syncTagSelectedStatus();
  } catch {
    // 自动识别失败不阻塞表单，保存时后端仍会再次解析能力。
  } finally {
    if (requestSequence === capabilityRequestSequence) {
      capabilityLoading.value = false;
    }
  }
};

const rules = {
  title: [{ required: true, message: $t('message.required'), trigger: 'blur' }],
  modelName: [
    { required: true, message: $t('message.required'), trigger: 'blur' },
  ],
  groupName: [
    { required: true, message: $t('message.required'), trigger: 'blur' },
  ],
};

const save = async () => {
  btnLoading.value = true;
  const modelType = resolveModelType();

  try {
    await formDataRef.value.validate();
    const submitData = {
      ...formData,
      modelType,
      providerId: isAdd.value ? selectedProviderId.value : formData.providerId,
    };

    const url = isAdd.value ? '/api/v1/model/save' : '/api/v1/model/update';
    const res = await api.post(url, submitData);

    if (res.errorCode === 0) {
      ElMessage.success(res.message);
      emit('reload');
      closeDialog();
    } else {
      ElMessage.error(res.message || $t('ui.actionMessage.operationFailed'));
    }
  } catch (error) {
    if (!(error as any)?.fields) {
      ElMessage.error($t('ui.actionMessage.operationFailed'));
    }
  } finally {
    btnLoading.value = false;
  }
};
</script>

<template>
  <EasyFlowFormModal
    v-model:open="dialogVisible"
    :centered="true"
    :closable="!btnLoading"
    :title="isAdd ? '添加模型' : '编辑模型'"
    :before-close="closeDialog"
    width="640"
    :confirm-loading="btnLoading"
    :confirm-text="$t('button.save')"
    :submitting="btnLoading"
    @confirm="save"
  >
    <div class="model-modal">
      <ElForm
        ref="formDataRef"
        :model="formData"
        status-icon
        :rules="rules"
        label-position="top"
        class="model-modal__form"
      >
        <div class="model-modal__section">
          <ElFormItem prop="title" :label="$t('llm.title')">
            <ElInput
              v-model.trim="formData.title"
              placeholder="例如：生产主模型"
            />
          </ElFormItem>
          <ElFormItem prop="modelName" :label="$t('llm.llmModel')">
            <ElInput
              v-model.trim="formData.modelName"
              placeholder="例如：gpt-4.1 / glm-4.5 / qwen3:8b"
              @blur="detectModelCapabilities"
              @input="handleModelNameInput"
            />
          </ElFormItem>
          <ElFormItem prop="groupName" :label="$t('llm.groupName')">
            <ElInput
              v-model.trim="formData.groupName"
              placeholder="例如：默认组"
            />
          </ElFormItem>

          <ElFormItem class="model-modal__ability-item">
            <template #label>
              <span class="model-modal__ability-label">
                {{ $t('llm.ability') }}
                <ElTooltip
                  :content="$t('llm.abilityChangeTip')"
                  effect="light"
                  placement="top"
                >
                  <button
                    type="button"
                    class="model-modal__ability-info"
                    :aria-label="$t('llm.abilityChangeTip')"
                  >
                    <ElIcon><InfoFilled /></ElIcon>
                  </button>
                </ElTooltip>
              </span>
            </template>
            <div
              class="model-modal__ability-panel"
              :aria-busy="capabilityLoading"
            >
              <div class="model-modal__ability-toolbar">
                <button
                  v-for="item in modelTypeAbilityOptions"
                  :key="item.value"
                  type="button"
                  class="model-modal__ability-chip is-interactive"
                  :class="[
                    `is-tone-${item.value}`,
                    { 'is-active': selectedModelType === item.value },
                  ]"
                  :aria-pressed="selectedModelType === item.value"
                  @click="handleModelTypeChipClick(item.value)"
                >
                  <IconifyIcon
                    :icon="getAbilityIcon(item.value)"
                    class="model-modal__ability-icon"
                  />
                  {{ item.label }}
                </button>
                <span
                  class="model-modal__ability-separator"
                  aria-hidden="true"
                ></span>
                <button
                  v-for="item in visibleModelAbility"
                  :key="item.value"
                  type="button"
                  class="model-modal__ability-chip is-interactive"
                  :class="{
                    'is-active': item.selected,
                    'is-disabled': hasSpecialModelType,
                    [`is-tone-${item.value}`]: true,
                  }"
                  :aria-pressed="item.selected"
                  :disabled="hasSpecialModelType"
                  @click="handleAbilityChipClick(item)"
                >
                  <IconifyIcon
                    :icon="getAbilityIcon(item.value)"
                    class="model-modal__ability-icon"
                  />
                  {{ item.label }}
                </button>
                <ElIcon
                  v-if="capabilityLoading"
                  class="model-modal__ability-loading is-loading"
                  aria-label="正在识别模型能力"
                >
                  <Loading />
                </ElIcon>
              </div>
            </div>
          </ElFormItem>

          <div v-if="!hasSpecialModelType" class="model-modal__advanced">
            <button
              type="button"
              class="model-modal__advanced-toggle"
              :aria-expanded="showAdvanced"
              @click="showAdvanced = !showAdvanced"
            >
              <span>高级设置</span>
              <ElIcon>
                <ArrowUp v-if="showAdvanced" />
                <ArrowDown v-else />
              </ElIcon>
            </button>

            <div v-if="showAdvanced" class="model-modal__advanced-body">
              <ElFormItem label="Agent HTTP 传输">
                <ElSelect
                  v-model="formData.options.agentHttpVersionPolicy"
                  aria-label="Agent HTTP 传输"
                >
                  <ElOption
                    v-for="item in agentHttpVersionOptions"
                    :key="item.value"
                    :label="item.label"
                    :value="item.value"
                  />
                </ElSelect>
              </ElFormItem>
              <ElFormItem label="System 消息格式">
                <ElSelect
                  v-model="formData.options.agentSystemContentFormat"
                  aria-label="System 消息格式"
                >
                  <ElOption
                    v-for="item in agentSystemContentFormatOptions"
                    :key="item.value"
                    :label="item.label"
                    :value="item.value"
                  />
                </ElSelect>
              </ElFormItem>
            </div>
          </div>
        </div>
      </ElForm>
    </div>
  </EasyFlowFormModal>
</template>

<style scoped>
.model-modal {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.model-modal__section {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 16px 18px;
  background: hsl(var(--surface-panel) / 96%);
  border: 1px solid hsl(var(--divider-faint) / 42%);
  border-radius: 20px;
}

.model-modal__form {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.model-modal__ability-item {
  margin-top: 4px;
}

.model-modal__ability-label {
  display: inline-flex;
  gap: var(--space-1);
  align-items: center;
}

.model-modal__ability-info {
  display: inline-flex;
  padding: 0;
  color: hsl(var(--text-muted));
  cursor: help;
  background: transparent;
  border: 0;
  border-radius: var(--radius-control);
  transition: color var(--motion-duration-base) var(--motion-ease-standard);
}

.model-modal__ability-info:hover,
.model-modal__ability-info:focus-visible {
  color: hsl(var(--primary));
}

.model-modal__ability-info:focus-visible {
  outline: 2px solid hsl(var(--primary) / 24%);
  outline-offset: 2px;
}

.model-modal__ability-panel {
  padding: 2px;
  overflow: hidden;
  border-radius: 18px;
}

.model-modal__ability-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
}

.model-modal__ability-separator {
  align-self: stretch;
  width: 1px;
  min-height: 28px;
  background: hsl(var(--divider-faint) / 62%);
  border-radius: 999px;
}

.model-modal__ability-chip {
  display: inline-flex;
  gap: 8px;
  align-items: center;
  justify-content: center;
  min-height: 40px;
  padding: 9px 18px;
  font-size: 13px;
  font-weight: 600;
  line-height: 1;
  color: hsl(var(--text-muted));
  cursor: default;
  background: hsl(var(--surface-contrast-soft) / 86%);
  border: 1px solid transparent;
  border-radius: 999px;
  transition:
    transform 0.2s ease,
    border-color 0.2s ease,
    color 0.2s ease,
    background 0.2s ease,
    box-shadow 0.2s ease;
}

.model-modal__ability-chip.is-interactive {
  cursor: pointer;
}

.model-modal__ability-chip.is-interactive:hover,
.model-modal__ability-chip.is-interactive:focus-visible {
  color: hsl(var(--text-strong));
  box-shadow: 0 10px 18px -14px hsl(var(--foreground) / 28%);
  transform: translateY(-1px);
}

.model-modal__ability-chip.is-active {
  color: hsl(var(--text-strong));
  background: hsl(var(--primary) / 10%);
  border-color: hsl(var(--primary) / 18%);
  box-shadow: inset 0 0 0 1px hsl(var(--primary) / 14%);
}

.model-modal__ability-chip.is-disabled {
  cursor: default;
  box-shadow: none;
  opacity: 0.56;
  transform: none;
}

.model-modal__ability-icon {
  font-size: 15px;
  opacity: 0.88;
}

.model-modal__ability-loading {
  margin-inline-start: var(--space-1);
  color: hsl(var(--text-muted));
}

.model-modal__ability-chip.is-active.is-tone-embeddingModel,
.model-modal__ability-chip.is-active.is-tone-thinking {
  color: hsl(var(--primary));
  background: hsl(var(--primary) / 10%);
  border-color: hsl(var(--primary) / 18%);
  box-shadow: inset 0 0 0 1px hsl(var(--primary) / 14%);
}

.model-modal__ability-chip.is-active.is-tone-rerankModel,
.model-modal__ability-chip.is-active.is-tone-tool {
  color: hsl(var(--warning));
  background: hsl(var(--warning) / 12%);
  border-color: hsl(var(--warning) / 18%);
  box-shadow: inset 0 0 0 1px hsl(var(--warning) / 14%);
}

.model-modal__ability-chip.is-active.is-tone-image {
  color: hsl(var(--success));
  background: hsl(var(--success) / 12%);
  border-color: hsl(var(--success) / 18%);
  box-shadow: inset 0 0 0 1px hsl(var(--success) / 14%);
}

.model-modal__advanced {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.model-modal__advanced-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: var(--space-2) var(--space-3);
  font-size: 13px;
  color: hsl(var(--text-muted));
  cursor: pointer;
  background: hsl(var(--surface-contrast-soft) / 68%);
  border: 1px solid hsl(var(--divider-faint) / 56%);
  border-radius: var(--radius-control);
  transition:
    color var(--motion-duration-base) var(--motion-ease-standard),
    border-color var(--motion-duration-base) var(--motion-ease-standard),
    background var(--motion-duration-base) var(--motion-ease-standard);
}

.model-modal__advanced-toggle:hover,
.model-modal__advanced-toggle:focus-visible {
  color: hsl(var(--text-strong));
  background: hsl(var(--surface-contrast-soft));
  border-color: hsl(var(--divider-faint));
}

.model-modal__advanced-body :deep(.el-form-item) {
  margin-bottom: 0;
}

.model-modal__advanced-body {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.model-modal__advanced-body :deep(.el-select) {
  width: 100%;
}

@media (max-width: 640px) {
  .model-modal__ability-separator {
    display: none;
  }
}
</style>
