<script setup>
import Button from "@/components/ui/Button.vue";
import Select from "@/components/ui/Select.vue";
import Tooltip from "@/components/ui/Tooltip.vue";
import {
  ANTHROPIC_THINKING_EFFORT_DEFAULT,
  createEmptyModelAdapter,
  normalizeModelAdapter,
  OPENAI_ENDPOINT_CHAT_COMPLETIONS,
  OPENAI_ENDPOINT_CUSTOM,
  OPENAI_ENDPOINT_RESPONSES,
  OPENAI_EXTRA_PARAMS_DEFAULT_JSON,
} from "@/state/appState";
import { computed, reactive, watch } from "vue";

const modelTypeOptions = [
  { label: "openai", value: "openai", icon: "icon-[bxl--openai]" },
  { label: "anthropic", value: "anthropic", icon: "icon-[logos--claude-icon]" },
];

const reasoningEffortOptions = [
  { label: "不设置", value: "", icon: "icon-[mdi--minus-circle-outline]" },
  { label: "低", value: "low", icon: "icon-[mdi--head-outline]" },
  { label: "中", value: "medium", icon: "icon-[mdi--head-lightbulb-outline]" },
  { label: "高", value: "high", icon: "icon-[mdi--brain]" },
  { label: "极高", value: "xhigh", icon: "icon-[mdi--head-cog-outline]" },
  { label: "最高", value: "max", icon: "icon-[mdi--brain]" },
];

const anthropicThinkingEffortOptions = [
  { label: "低", value: "low", icon: "icon-[mdi--head-outline]" },
  { label: "中", value: "medium", icon: "icon-[mdi--head-lightbulb-outline]" },
  { label: "高", value: "high", icon: "icon-[mdi--brain]" },
  { label: "极高", value: "xhigh", icon: "icon-[mdi--head-cog-outline]" },
  { label: "最大", value: "max", icon: "icon-[mdi--brain]" },
];

const openAIEndpointOptions = [
  { label: "/v1/responses", value: OPENAI_ENDPOINT_RESPONSES, icon: "icon-[mdi--api]" },
  { label: "/v1/chat/completions", value: OPENAI_ENDPOINT_CHAT_COMPLETIONS, icon: "icon-[mdi--message-text-outline]" },
  { label: "自定义路径", value: OPENAI_ENDPOINT_CUSTOM, icon: "icon-[mdi--pencil-outline]" },
];

const fieldTips = {
  openAIExtraParams: "开启后会把 JSON 对象覆盖到 OpenAI 请求体。同名字段以这里为准。OpenAI service_tier 支持 auto、default、flex、scale、priority；priority 可用于高优先级/Fast 类场景。",
};

const props = defineProps({
  visible: { type: Boolean, default: false },
  title: { type: String, default: "模型配置" },
  adapter: {
    type: Object,
    default: () => createEmptyModelAdapter(),
  },
});

const emit = defineEmits(["cancel", "save"]);

const draft = reactive(createEmptyModelAdapter());

function createOptionalPositiveIntegerModel(key) {
  return computed({
    get() {
      return draft[key] > 0 ? String(draft[key]) : "";
    },
    set(value) {
      const text = String(value || "").trim();
      draft[key] = /^\d+$/.test(text) && Number(text) > 0 ? Number(text) : 0;
    },
  });
}

const maxCompletionTokensInput = createOptionalPositiveIntegerModel("maxCompletionTokens");
const anthropicMaxTokensInput = createOptionalPositiveIntegerModel("anthropicMaxTokens");
const contextWindowTokensInput = createOptionalPositiveIntegerModel("contextWindowTokens");

function ensureOpenAIExtraParamsJSON() {
  if (!String(draft.openAIExtraParamsJSON || "").trim()) {
    draft.openAIExtraParamsJSON = OPENAI_EXTRA_PARAMS_DEFAULT_JSON;
  }
}

function ensureAnthropicThinkingEffort() {
  if (!String(draft.anthropicThinkingEffort || "").trim()) {
    draft.anthropicThinkingEffort = ANTHROPIC_THINKING_EFFORT_DEFAULT;
  }
}

function syncDraft() {
  Object.assign(draft, normalizeModelAdapter(props.adapter));
  if (!draft.type) {
    draft.type = "openai";
  }
}

watch(() => props.visible, (visible) => {
  if (visible) {
    syncDraft();
  }
}, { immediate: true });

watch(() => props.adapter, () => {
  if (props.visible) {
    syncDraft();
  }
});

watch(() => draft.type, (type) => {
  if (type === "openai" && !draft.openAIEndpoint) {
    draft.openAIEndpoint = OPENAI_ENDPOINT_RESPONSES;
  } else if (type === "anthropic") {
    ensureAnthropicThinkingEffort();
  }
});

watch(() => draft.openAIExtraParamsEnabled, (enabled) => {
  if (enabled) {
    ensureOpenAIExtraParamsJSON();
  }
});

function handleCancel() {
  emit("cancel");
}

function handleSave() {
  emit("save", normalizeModelAdapter(draft));
}
</script>

<template>
  <Teleport to="body">
    <Transition name="modal-mask">
      <div
        v-show="visible"
        class="fixed inset-0 z-999 flex items-center justify-center bg-black/50 p-4"
        @click.self="handleCancel"
      >
        <Transition name="modal-content">
          <div
            v-show="visible"
            class="relative z-10 w-full max-w-[560px] overflow-hidden rounded-[8px] p-px shadow-[0_25px_50px_-12px_rgba(0,0,0,0.6)]"
            style="background: linear-gradient(to bottom, #656565 0%, #3A3A3A 10px, #3A3A3A 100%);"
            @click.stop
          >
            <div class="rounded-[7px] bg-[#292929] p-5">
              <h3 class="mb-4 text-base font-medium text-white">{{ title }}</h3>

              <div class="grid grid-cols-1 gap-3 md:grid-cols-2">
                <label class="flex flex-col gap-1">
                  <span class="text-sm text-[#d4d4d4]">显示名称</span>
                  <input
                    v-model="draft.displayName"
                    type="text"
                    class="h-9 rounded-[6px] border border-[#3f3f3f] bg-[#232323] px-3 text-sm text-[#e5e5e5] outline-none focus:border-[#10AD5D]"
                  />
                </label>

                <label class="flex flex-col gap-1">
                  <span class="text-sm text-[#d4d4d4]">ModelID</span>
                  <input
                    v-model="draft.modelID"
                    type="text"
                    class="h-9 rounded-[6px] border border-[#3f3f3f] bg-[#232323] px-3 text-sm text-[#e5e5e5] outline-none focus:border-[#10AD5D]"
                  />
                </label>

                <label class="flex flex-col gap-1">
                  <span class="text-sm text-[#d4d4d4]">类型</span>
                  <Select
                    v-model="draft.type"
                    :options="modelTypeOptions"
                  />
                </label>

                <label class="flex flex-col gap-1">
                  <span class="text-sm text-[#d4d4d4]">API Key</span>
                  <input
                    v-model="draft.apiKey"
                    type="text"
                    class="h-9 rounded-[6px] border border-[#3f3f3f] bg-[#232323] px-3 text-sm text-[#e5e5e5] outline-none focus:border-[#10AD5D]"
                  />
                </label>
              </div>

              <label class="mt-3 flex flex-col gap-1">
                <span class="text-sm text-[#d4d4d4]">baseURL</span>
                <input
                  v-model="draft.baseURL"
                  type="text"
                  class="h-9 rounded-[6px] border border-[#3f3f3f] bg-[#232323] px-3 text-sm text-[#e5e5e5] outline-none focus:border-[#10AD5D]"
                />
              </label>

              <label class="mt-3 flex flex-col gap-1">
                <span class="text-sm text-[#d4d4d4]">context_window_tokens</span>
                <input
                  v-model="contextWindowTokensInput"
                  type="text"
                  inputmode="numeric"
                  placeholder="留空时默认 200000"
                  class="h-9 rounded-[6px] border border-[#3f3f3f] bg-[#232323] px-3 text-sm text-[#e5e5e5] outline-none focus:border-[#10AD5D]"
                />
              </label>

              <div v-if="draft.type === 'openai'" class="mt-3 grid grid-cols-1 gap-3 md:grid-cols-2">
                <label class="flex flex-col gap-1">
                  <span class="text-sm text-[#d4d4d4]">reasoning_effort</span>
                  <Select
                    v-model="draft.reasoningEffort"
                    :options="reasoningEffortOptions"
                  />
                </label>

                <label class="flex flex-col gap-1">
                  <span class="text-sm text-[#d4d4d4]">max token</span>
                  <input
                    v-model="maxCompletionTokensInput"
                    type="text"
                    inputmode="numeric"
                    placeholder="留空时默认 65536"
                    class="h-9 rounded-[6px] border border-[#3f3f3f] bg-[#232323] px-3 text-sm text-[#e5e5e5] outline-none focus:border-[#10AD5D]"
                  />
                </label>

                <label class="flex flex-col gap-1">
                  <span class="text-sm text-[#d4d4d4]">endpoint</span>
                  <Select
                    v-model="draft.openAIEndpoint"
                    :options="openAIEndpointOptions"
                  />
                </label>
              </div>

              <div v-if="draft.type === 'openai'" class="mt-3 rounded-[8px] border border-[#343434] bg-[#252525] p-3">
                <div class="flex items-center justify-between gap-3">
                  <span class="flex items-center gap-1.5 text-sm text-[#d4d4d4]">
                    <Tooltip :content="fieldTips.openAIExtraParams" />
                    <span>额外参数 JSON</span>
                  </span>
                  <label class="flex items-center gap-2 text-xs text-[#d4d4d4]">
                    <input
                      v-model="draft.openAIExtraParamsEnabled"
                      type="checkbox"
                      class="size-4 accent-[#10AD5D]"
                    />
                    <span>启用</span>
                  </label>
                </div>
                <textarea
                  v-if="draft.openAIExtraParamsEnabled"
                  v-model="draft.openAIExtraParamsJSON"
                  rows="5"
                  spellcheck="false"
                  class="mt-3 min-h-[120px] w-full resize-none rounded-[6px] border border-[#3f3f3f] bg-[#1f1f1f] px-3 py-2 font-mono text-xs text-[#e5e5e5] outline-none focus:border-[#10AD5D]"
                />
              </div>

              <div v-if="draft.type === 'anthropic'" class="mt-3 grid grid-cols-1 gap-3 md:grid-cols-2">
                <label class="flex flex-col gap-1">
                  <span class="text-sm text-[#d4d4d4]">max_tokens</span>
                  <input
                    v-model="anthropicMaxTokensInput"
                    type="text"
                    inputmode="numeric"
                    placeholder="留空时默认 65536"
                    class="h-9 rounded-[6px] border border-[#3f3f3f] bg-[#232323] px-3 text-sm text-[#e5e5e5] outline-none focus:border-[#10AD5D]"
                  />
                </label>

                <label class="flex flex-col gap-1">
                  <span class="text-sm text-[#d4d4d4]">thinking effort</span>
                  <Select
                    v-model="draft.anthropicThinkingEffort"
                    :options="anthropicThinkingEffortOptions"
                  />
                </label>
              </div>

              <label class="mt-3 flex flex-col gap-1">
                <span class="text-sm text-[#d4d4d4]">tooltipData</span>
                <textarea
                  v-model="draft.tooltipData"
                  rows="5"
                  class="min-h-[120px] resize-none rounded-[6px] border border-[#3f3f3f] bg-[#232323] px-3 py-2 text-sm text-[#e5e5e5] outline-none focus:border-[#10AD5D]"
                />
              </label>

              <div class="mt-5 flex justify-end gap-2">
                <Button variant="default" @click="handleCancel">取消</Button>
                <Button variant="primary" @click="handleSave">保存</Button>
              </div>
            </div>
          </div>
        </Transition>
      </div>
    </Transition>
  </Teleport>
</template>

<style scoped>
.modal-mask-enter-active,
.modal-mask-leave-active {
  transition: opacity 0.25s ease, backdrop-filter 0.25s ease;
}
.modal-mask-enter-from,
.modal-mask-leave-to {
  opacity: 0;
  backdrop-filter: blur(0);
}

.modal-content-enter-active,
.modal-content-leave-active {
  transition: all 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
}
.modal-content-enter-from,
.modal-content-leave-to {
  opacity: 0;
  transform: scale(0.9) translateY(-10px);
}
</style>
