<script lang="ts" setup>
/**
 * 金方导入弹窗（PC 接诊 / 在线复诊共用）
 * - VIP：golden_formula
 * - 支持来源筛选；异常方标记不可选；方名后展示绑定来源
 * - 选方后调用药名对照，确认导入时抛出与 AI 出方相同结构的 rows
 */
import { ref } from 'vue';

import { useVbenModal } from '@vben/common-ui';

import {
  Button,
  Empty,
  Input,
  Select,
  Spin,
  Tag,
  message,
} from 'ant-design-vue';

import {
  goldenFormulaApplyApi,
  goldenFormulaListApi,
  goldenFormulaSaveMatchApi,
  goldenFormulaSourceOptionApi,
} from '../api';

const emit = defineEmits<{
  (
    e: 'import',
    payload: {
      rows: Array<Record<string, any>>;
      formulaName?: string;
    },
  ): void;
}>();

const loading = ref(false);
const applying = ref(false);
const keyword = ref('');
/** 金方来源筛选（0=全部） */
const sourceId = ref<number | undefined>(undefined);
const sourceOptions = ref<Array<{ label: string; value: number }>>([]);
const list = ref<any[]>([]);
const total = ref(0);
const page = ref(1);
const pageSize = 20;
const storeId = ref(0);
const registerId = ref(0);
/** 处方类型：1中药 2西药（与 ProductTypeEnum 对齐；接诊 activeCategory 1=中 2=西） */
const prescriptionType = ref(1);
const selectedId = ref(0);
const matchResult = ref<any | null>(null);

const [Modal, modalApi] = useVbenModal({
  fullscreenButton: false,
  draggable: true,
  footer: false,
  class: 'w-[880px]',
  onCancel() {
    modalApi.close();
  },
  onOpenChange(isOpen: boolean) {
    if (!isOpen) {
      keyword.value = '';
      sourceId.value = undefined;
      list.value = [];
      matchResult.value = null;
      selectedId.value = 0;
      return;
    }
    const data = modalApi.getData<{
      storeId?: number;
      registerId?: number;
      /** 开方页 activeCategory：1中药 2西药 → ProductType 同值 */
      category?: number;
    }>() || {};
    storeId.value = Number(data.storeId || 0);
    registerId.value = Number(data.registerId || 0);
    // activeCategory 1=中药 2=西药，与 ProductTypeEnum 一致
    prescriptionType.value = Number(data.category || 1) === 2 ? 2 : 1;
    page.value = 1;
    loadSources();
    loadList();
  },
});

/**
 * 加载金方来源下拉，供顶部筛选
 */
async function loadSources() {
  try {
    const res = await goldenFormulaSourceOptionApi({
      store_id: storeId.value || undefined,
    });
    const rows = Array.isArray(res) ? res : res?.items || [];
    sourceOptions.value = rows.map((r: any) => ({
      label: r.name,
      value: Number(r.id),
    }));
  } catch {
    sourceOptions.value = [];
  }
}

/** 加载金方列表 */
async function loadList() {
  loading.value = true;
  matchResult.value = null;
  selectedId.value = 0;
  try {
    const res = await goldenFormulaListApi({
      keyword: keyword.value,
      page: page.value,
      pageSize,
      store_id: storeId.value || undefined,
      source_id: sourceId.value || undefined,
    });
    list.value = res?.items || [];
    total.value = Number(res?.total || 0);
  } catch (e: any) {
    message.error(e?.message || '加载金方失败');
  } finally {
    loading.value = false;
  }
}

function onSearch() {
  page.value = 1;
  loadList();
}

/** 切换来源筛选后回到第一页重载 */
function onSourceChange() {
  page.value = 1;
  loadList();
}

/**
 * 列表展示名：方名（来源）；无来源则只显示方名
 */
function displayName(item: any): string {
  const name = item?.name || '';
  const source = item?.source_name || item?.source || '';
  return source ? `${name}（${source}）` : name;
}

/** 是否异常方（不可选） */
function isAbnormal(item: any): boolean {
  return Number(item?.is_abnormal ?? 0) === 1 || Number(item?.selectable ?? 1) === 0;
}

/**
 * 选中金方并做药名对照；异常方直接提示不可选
 */
async function handleSelect(row: any) {
  if (isAbnormal(row)) {
    message.warning('该金方为异常方，无法选择导入');
    return;
  }
  selectedId.value = Number(row.id);
  applying.value = true;
  matchResult.value = null;
  try {
    const res = await goldenFormulaApplyApi({
      id: selectedId.value,
      store_id: storeId.value || undefined,
      register_id: registerId.value || undefined,
      prescription_type: prescriptionType.value,
    });
    // 规范化：保证每行有 candidates + selected_drug_id，便于点选切换
    matchResult.value = normalizeMatchPayload(res);
  } catch (e: any) {
    message.error(e?.message || '对照失败');
  } finally {
    applying.value = false;
  }
}

/**
 * 规范化对照结果：缺省 selected_drug_id 时取候选第一项
 */
function normalizeMatchPayload(payload: any) {
  if (!payload) return null;
  const matched = (payload.matched || []).map((m: any) => {
    const candidates = Array.isArray(m.candidates) ? m.candidates : [];
    let sid = Number(m.selected_drug_id || 0);
    if (!sid && candidates.length) {
      sid = Number(candidates[0].drug_id || 0);
    }
    return { ...m, candidates, selected_drug_id: sid };
  });
  return { ...payload, matched };
}

/**
 * 组装当前对照行的匹配记忆 items，供落库
 */
function buildMatchSaveItems(matched: any[]) {
  return matched
    .map((m: any) => {
      const candidates = m.candidates || [];
      const sid = Number(m.selected_drug_id || 0);
      const picked =
        candidates.find((c: any) => Number(c.drug_id) === sid) ||
        candidates[0] ||
        {};
      const drugId = Number(picked.drug_id || sid || 0);
      const drugName = String(m.ai_name || '').trim();
      if (!drugName || !drugId) return null;
      return {
        drug_name: drugName,
        selected_drug_id: drugId,
        selected_drug_name: String(picked.drug_name || ''),
      };
    })
    .filter(Boolean) as Array<{
    drug_name: string;
    selected_drug_id: number;
    selected_drug_name?: string;
  }>;
}

/**
 * 持久化医生匹配记忆（失败不阻断导入）
 */
async function persistDoctorMatches(items: Array<{
  drug_name: string;
  selected_drug_id: number;
  selected_drug_name?: string;
}>) {
  if (!selectedId.value || !items.length) return;
  try {
    await goldenFormulaSaveMatchApi({
      id: selectedId.value,
      store_id: storeId.value || undefined,
      items,
    });
  } catch (e) {
    console.warn('金方匹配记忆保存失败', e);
  }
}

/**
 * 点击候选药品：更新该行 selected_drug_id，并立即落库记忆
 */
async function onPickCandidate(mi: number, candidate: any) {
  const list = matchResult.value?.matched;
  if (!list || !list[mi] || !candidate) return;
  const drugId = Number(candidate.drug_id || 0);
  if (!drugId) return;
  if (Number(list[mi].selected_drug_id) === drugId) return;
  list[mi].selected_drug_id = drugId;
  const drugName = String(list[mi].ai_name || '').trim();
  if (!drugName) return;
  await persistDoctorMatches([
    {
      drug_name: drugName,
      selected_drug_id: drugId,
      selected_drug_name: String(candidate.drug_name || ''),
    },
  ]);
}

/**
 * 确认导入：把 matched 转成 AI 导入同构 rows（按当前选中候选）
 * 剂量：直接用后端 apply 已处理好的 m.dose（有小数已进位到整数克），禁止前端再改
 */
async function handleConfirmImport() {
  const matched = matchResult.value?.matched || [];
  if (!matched.length) {
    message.warning('没有可导入的已匹配药品');
    return;
  }
  // 确认导入前再整批落库，保证下次自动选中
  await persistDoctorMatches(buildMatchSaveItems(matched));
  const rows = matched.map((m: any) => {
    const candidates = m.candidates || [];
    const selectedDrugId = Number(m.selected_drug_id || 0);
    const candidate =
      candidates.find((c: any) => Number(c.drug_id) === selectedDrugId) ||
      candidates[0] ||
      {};
    return {
      // 以下 || '' 兜底对齐 AI 出方协议（AiPrescriptionDrawer.vue onConfirmImport），
      // 避免 undefined 进入 handleImportAiPrescription 后：
      // - dose 为 undefined → parseFloat NaN → 回退 1，丢失真实剂量
      // - unit 为 undefined → 中药卡片单位显示异常
      // - usage 为 undefined → wayId 解析失败
      ai_name: m.ai_name || '',
      // 后端 enrich 已对原始剂量做小数进位（如 46.88→47）
      dose: m.dose || '',
      unit: m.unit || '',
      usage: m.usage || '',
      frequency: m.frequency || '',
      candidate,
    };
  });
  emit('import', {
    rows,
    formulaName: matchResult.value?.formula?.name || '',
  });
  const unmatched = matchResult.value?.unmatched || [];
  if (unmatched.length) {
    message.warning(
      `已导入 ${rows.length} 味；未匹配 ${unmatched.length} 味请手动补录`,
    );
  } else {
    message.success(`已导入金方：${matchResult.value?.formula?.name || ''}`);
  }
  modalApi.close();
}

defineExpose({
  open: (data: Record<string, any>) => {
    modalApi.setData(data);
    modalApi.open();
  },
});
</script>
<template>
  <Modal title="导入金方" class="w-[50%] h-[80%]">
    <!-- 颜色一律用主题变量，禁止写死亮色底（暗色模式可读） -->
    <div class="gf-modal flex gap-3 text-foreground" style="min-height: 420px">
      <div class="w-[340px] shrink-0 border-r border-border pr-3">
        <div class="mb-2 flex gap-2">
          <Select
            v-model:value="sourceId"
            allow-clear
            class="w-[120px] shrink-0"
            placeholder="来源"
            :options="sourceOptions"
            @change="onSourceChange"
          />
          <Input
            v-model:value="keyword"
            allow-clear
            placeholder="名称/首拼/全拼/来源/速览"
            @press-enter="onSearch"
          />
          <Button type="primary" @click="onSearch">搜索</Button>
        </div>
        <Spin :spinning="loading">
          <div v-if="!list.length" class="py-8">
            <Empty description="暂无金方" />
          </div>
          <div v-else class="max-h-[550px] space-y-2 overflow-y-auto">
            <div
              v-for="item in list"
              :key="item.id"
              class="gf-item rounded border border-border bg-card p-2 transition"
              :class="{
                'gf-item--active': selectedId === item.id,
                'gf-item--disabled': isAbnormal(item),
                'cursor-pointer hover:border-primary': !isAbnormal(item),
              }"
              @click="handleSelect(item)"
            >
              <div class="font-medium text-foreground">
                {{ displayName(item) }}
                <Tag v-if="isAbnormal(item)" color="error" class="ml-1">异常</Tag>
              </div>
              <div class="mt-1 line-clamp-2 text-xs text-muted-foreground">
                {{ item.herb_overview || '—' }}
              </div>
            </div>
          </div>
          <div
            v-if="total > pageSize"
            class="mt-2 text-center text-xs text-muted-foreground"
          >
            共 {{ total }} 条（当前第 {{ page }} 页）
            <Button
              v-if="page * pageSize < total"
              type="link"
              size="small"
              @click="page += 1; loadList()"
            >
              下一页
            </Button>
          </div>
        </Spin>
      </div>
      <div class="min-w-0 flex-1">
        <Spin :spinning="applying">
          <div v-if="!matchResult" class="py-16">
            <Empty description="请选择左侧金方进行药名对照" />
          </div>
          <div v-else>
            <div class="mb-2 text-base font-medium text-foreground">
              {{
                matchResult.formula?.source_name || matchResult.formula?.source
                  ? `${matchResult.formula?.name || ''}（${matchResult.formula.source_name || matchResult.formula.source}）`
                  : matchResult.formula?.name
              }}
            </div>
            <div
              v-if="matchResult.formula?.indication_translation || matchResult.formula?.indication_original"
              class="mb-2 text-xs text-muted-foreground"
            >
              主治：
              {{
                matchResult.formula.indication_translation ||
                matchResult.formula.indication_original
              }}
            </div>
            <div
              v-if="matchResult.formula?.original_formula"
              class="gf-original mb-2 max-h-24 overflow-y-auto rounded px-2 py-1 text-xs whitespace-pre-wrap"
            >
              <span class="gf-original__label font-medium">原方：</span>
              {{ matchResult.formula.original_formula }}
            </div>
            <div class="mb-2 text-sm text-foreground">
              已匹配
              <Tag color="success">{{ (matchResult.matched || []).length }}</Tag>
              未匹配
              <Tag color="warning">{{ (matchResult.unmatched || []).length }}</Tag>
            </div>
            <div class="max-h-[280px] space-y-2 overflow-y-auto text-sm">
              <!-- 与 AI 出方一致：一行一药 + 全部候选 Tag 可点选 -->
              <div
                v-for="(m, mi) in matchResult.matched || []"
                :key="'m' + mi"
                class="gf-matched rounded px-2.5 py-2"
              >
                <div class="font-medium text-foreground">
                  {{
                    m.show_dose ||
                    m.display_text ||
                    `${m.ai_name} ${m.dose || ''}${m.unit || ''}${m.usage ? `（${m.usage}）` : ''}`
                  }}
                </div>
                <div class="mt-1.5 flex flex-wrap gap-1">
                  <Tag
                    v-for="c in m.candidates || []"
                    :key="c.drug_id"
                    class="cursor-pointer !m-0 !text-[11px]"
                    :color="
                      Number(m.selected_drug_id) === Number(c.drug_id)
                        ? 'success'
                        : undefined
                    "
                    @click="onPickCandidate(mi, c)"
                  >
                    {{ c.drug_name }}
                  </Tag>
                  <span
                    v-if="!(m.candidates || []).length"
                    class="text-xs text-muted-foreground"
                  >
                    无候选
                  </span>
                </div>
              </div>
              <div
                v-for="(u, idx) in matchResult.unmatched || []"
                :key="'u' + idx"
                class="gf-unmatched rounded px-2 py-1"
              >
                {{ u.show_dose || u.display_text || `${u.ai_name} ${u.dose || ''}${u.unit || ''}` }}
                （未匹配）
              </div>
            </div>
            <div class="mt-4 text-right">
              <Button
                type="primary"
                :disabled="!(matchResult.matched || []).length"
                @click="handleConfirmImport"
              >
                确认导入到处方
              </Button>
            </div>
          </div>
        </Spin>
      </div>
    </div>
  </Modal>
</template>
<style scoped>
/* 选中项：primary 透明度，暗色自动跟主题 */
.gf-item--active {
  border-color: hsl(var(--primary)) !important;
  background-color: hsl(var(--primary) / 0.1);
}
/* 异常方：灰显 + 禁止指针，表达不可选 */
.gf-item--disabled {
  cursor: not-allowed;
  opacity: 0.55;
  background-color: hsl(var(--muted) / 0.35);
}
/* 原方展示区：用 warning 变量，禁止 bg-amber-50 / text-amber-700 */
.gf-original {
  background-color: hsl(var(--warning) / 0.12);
  color: hsl(var(--foreground));
  border: 1px solid hsl(var(--warning) / 0.35);
}
.gf-original__label {
  color: hsl(var(--warning));
}
/* 已匹配：success/primary 浅绿底；暗色下半透明 */
.gf-matched {
  background-color: hsl(var(--primary) / 0.12);
  color: hsl(var(--foreground));
  border: 1px solid hsl(var(--primary) / 0.25);
}
/* 未匹配：warning 橙底 */
.gf-unmatched {
  background-color: hsl(var(--warning) / 0.12);
  color: hsl(var(--foreground));
  border: 1px solid hsl(var(--warning) / 0.35);
}
</style>
