<template>
  <AppShell>
    <div class="space-y-4">
      <div class="flex justify-between items-center">
        <h2 class="text-lg font-semibold">
          LLM Models
        </h2>
        <NButton
          type="primary"
          @click="openCreate"
        >
          + 新增
        </NButton>
      </div>
      <NDataTable
        :data="models"
        :columns="columns"
        :row-key="rowKey"
      />
      <NModal
        v-model:show="showForm"
        preset="card"
        title="LLM Model"
        style="width: 720px"
      >
        <NForm>
          <NFormItem label="Endpoint">
            <NSelect
              v-model:value="form.endpoint_id"
              :options="endpointOpts"
              :disabled="!!editing"
            />
          </NFormItem>
          <NFormItem label="Model ID（provider 侧）">
            <NInput
              v-model:value="form.model_id"
              :disabled="!!editing"
            />
          </NFormItem>
          <NFormItem label="显示名">
            <NInput v-model:value="form.display_name" />
          </NFormItem>
          <NFormItem label="能力">
            <div class="flex flex-wrap gap-3">
              <NCheckbox v-model:checked="form.capabilities.image">
                Image
              </NCheckbox>
              <NCheckbox v-model:checked="form.capabilities.pdf">
                PDF
              </NCheckbox>
              <NCheckbox v-model:checked="form.capabilities.audio">
                Audio
              </NCheckbox>
              <NCheckbox v-model:checked="form.capabilities.reasoning">
                Reasoning
              </NCheckbox>
              <NCheckbox v-model:checked="form.capabilities.tools">
                Tools
              </NCheckbox>
            </div>
          </NFormItem>
          <div class="grid grid-cols-2 gap-3">
            <NFormItem label="Context Window">
              <NInputNumber
                v-model:value="form.context_window"
                :min="1"
              />
            </NFormItem>
            <NFormItem label="Max Output Tokens">
              <NInputNumber
                v-model:value="form.max_output_tokens"
                :min="1"
              />
            </NFormItem>
            <NFormItem label="Prompt Price (USD / 1M)">
              <NInputNumber
                v-model:value="form.prompt_price_per_million_usd"
                :min="0"
                :step="0.01"
              />
            </NFormItem>
            <NFormItem label="Completion Price (USD / 1M)">
              <NInputNumber
                v-model:value="form.completion_price_per_million_usd"
                :min="0"
                :step="0.01"
              />
            </NFormItem>
            <NFormItem label="Thinking Price (USD / 1M)">
              <NInputNumber
                v-model:value="form.thinking_price_per_million_usd"
                :min="0"
                :step="0.01"
              />
            </NFormItem>
            <NFormItem label="Sort Order">
              <NInputNumber
                v-model:value="form.sort_order"
                :min="0"
              />
            </NFormItem>
          </div>
          <div class="flex gap-4 mt-2">
            <NCheckbox v-model:checked="form.enabled">
              Enabled
            </NCheckbox>
            <NCheckbox v-model:checked="form.is_title_generator">
              Title Generator
            </NCheckbox>
          </div>
        </NForm>
        <template #footer>
          <div class="flex justify-end gap-2">
            <NButton @click="showForm = false">
              取消
            </NButton>
            <NButton
              type="primary"
              :loading="saving"
              :disabled="!canSave"
              @click="save"
            >
              保存
            </NButton>
          </div>
        </template>
      </NModal>
    </div>
  </AppShell>
</template>

<script setup lang="ts">
import { computed, h, onMounted, ref } from 'vue'
import {
  NButton,
  NCheckbox,
  NDataTable,
  NForm,
  NFormItem,
  NInput,
  NInputNumber,
  NModal,
  NSelect,
  NTag,
  useDialog,
  useMessage,
} from 'naive-ui'
import type { DataTableColumns } from 'naive-ui'

import AppShell from '@/layouts/AppShell.vue'
import {
  llmAdminApi,
  type CreateModelBody,
  type LLMEndpoint,
  type LLMModel,
  type ModelCapabilities,
} from '@/api/llmAdmin'

const models = ref<LLMModel[]>([])
const endpoints = ref<LLMEndpoint[]>([])
const showForm = ref(false)
const editing = ref<LLMModel | null>(null)
const saving = ref(false)
const msg = useMessage()
const dlg = useDialog()

interface ModelForm {
  endpoint_id: string
  model_id: string
  display_name: string
  capabilities: ModelCapabilities
  context_window: number
  max_output_tokens: number
  prompt_price_per_million_usd: number
  completion_price_per_million_usd: number
  thinking_price_per_million_usd: number
  is_title_generator: boolean
  enabled: boolean
  sort_order: number
}

function blankForm(): ModelForm {
  return {
    endpoint_id: '',
    model_id: '',
    display_name: '',
    capabilities: {
      image: false,
      pdf: false,
      audio: false,
      reasoning: false,
      tools: false,
    },
    context_window: 200000,
    max_output_tokens: 8192,
    prompt_price_per_million_usd: 0,
    completion_price_per_million_usd: 0,
    thinking_price_per_million_usd: 0,
    is_title_generator: false,
    enabled: true,
    sort_order: 0,
  }
}

const form = ref<ModelForm>(blankForm())

const endpointOpts = computed(() =>
  endpoints.value.map((e) => ({
    label: `${e.display_name} (${e.provider})`,
    value: e.id,
  })),
)

const canSave = computed(() => {
  const f = form.value
  return (
    !!f.endpoint_id &&
    !!f.model_id.trim() &&
    !!f.display_name.trim() &&
    f.context_window > 0 &&
    f.max_output_tokens > 0
  )
})

const endpointName = (id: string) =>
  endpoints.value.find((e) => e.id === id)?.display_name ?? id

const capLabel = (c: ModelCapabilities) => {
  const parts: string[] = []
  if (c.image) parts.push('I')
  if (c.pdf) parts.push('P')
  if (c.audio) parts.push('A')
  if (c.reasoning) parts.push('R')
  if (c.tools) parts.push('T')
  return parts.join('') || '-'
}

const columns: DataTableColumns<LLMModel> = [
  { title: '显示名', key: 'display_name' },
  { title: 'Model ID', key: 'model_id' },
  {
    title: 'Endpoint',
    key: 'endpoint_id',
    render: (row) => endpointName(row.endpoint_id),
  },
  {
    title: '能力',
    key: 'capabilities',
    render: (row) => capLabel(row.capabilities),
  },
  { title: 'Ctx', key: 'context_window' },
  {
    title: '状态',
    key: 'enabled',
    render: (row) =>
      h(
        NTag,
        { type: row.enabled ? 'success' : 'default', size: 'small' },
        { default: () => (row.enabled ? '启用' : '停用') },
      ),
  },
  {
    title: 'Title?',
    key: 'is_title_generator',
    render: (row) => (row.is_title_generator ? '✓' : ''),
  },
  {
    title: '操作',
    key: 'actions',
    render: (row) =>
      h('div', { class: 'flex gap-1' }, [
        h(
          NButton,
          { size: 'small', onClick: () => openEdit(row) },
          { default: () => '编辑' },
        ),
        h(
          NButton,
          { size: 'small', type: 'error', onClick: () => del(row) },
          { default: () => '删除' },
        ),
      ]),
  },
]

const rowKey = (row: LLMModel) => row.id

onMounted(async () => {
  endpoints.value = await llmAdminApi.listEndpoints()
  await reload()
})

async function reload() {
  models.value = await llmAdminApi.listModels(false)
}

function openCreate() {
  editing.value = null
  form.value = blankForm()
  if (endpoints.value.length > 0) {
    form.value.endpoint_id = endpoints.value[0].id
  }
  showForm.value = true
}

function openEdit(m: LLMModel) {
  editing.value = m
  form.value = {
    endpoint_id: m.endpoint_id,
    model_id: m.model_id,
    display_name: m.display_name,
    capabilities: { ...m.capabilities },
    context_window: m.context_window,
    max_output_tokens: m.max_output_tokens,
    prompt_price_per_million_usd: m.prompt_price_per_million_usd,
    completion_price_per_million_usd: m.completion_price_per_million_usd,
    thinking_price_per_million_usd: m.thinking_price_per_million_usd,
    is_title_generator: m.is_title_generator,
    enabled: m.enabled,
    sort_order: m.sort_order,
  }
  showForm.value = true
}

async function save() {
  saving.value = true
  try {
    if (editing.value) {
      await llmAdminApi.updateModel(editing.value.id, {
        display_name: form.value.display_name,
        capabilities: form.value.capabilities,
        context_window: form.value.context_window,
        max_output_tokens: form.value.max_output_tokens,
        prompt_price_per_million_usd: form.value.prompt_price_per_million_usd,
        completion_price_per_million_usd:
          form.value.completion_price_per_million_usd,
        thinking_price_per_million_usd:
          form.value.thinking_price_per_million_usd,
        is_title_generator: form.value.is_title_generator,
        enabled: form.value.enabled,
        sort_order: form.value.sort_order,
      })
    } else {
      const body: CreateModelBody = {
        endpoint_id: form.value.endpoint_id,
        model_id: form.value.model_id,
        display_name: form.value.display_name,
        capabilities: form.value.capabilities,
        context_window: form.value.context_window,
        max_output_tokens: form.value.max_output_tokens,
        prompt_price_per_million_usd: form.value.prompt_price_per_million_usd,
        completion_price_per_million_usd:
          form.value.completion_price_per_million_usd,
        thinking_price_per_million_usd:
          form.value.thinking_price_per_million_usd,
        is_title_generator: form.value.is_title_generator,
        enabled: form.value.enabled,
        sort_order: form.value.sort_order,
      }
      await llmAdminApi.createModel(body)
    }
    msg.success('已保存')
    showForm.value = false
    await reload()
  } catch (e) {
    msg.error(e instanceof Error ? e.message : String(e))
  } finally {
    saving.value = false
  }
}

function del(m: LLMModel) {
  dlg.warning({
    title: `删除 ${m.display_name}？`,
    positiveText: '删除',
    negativeText: '取消',
    onPositiveClick: async () => {
      await llmAdminApi.deleteModel(m.id)
      await reload()
    },
  })
}
</script>
