<script lang="ts" setup>
/**
 * PC：AI 写病历
 * 主抽屉：生成历史 + 预览 + 确认导入
 * 二级弹窗：确认主诉后点生成 → 关弹窗，回抽屉等待结果
 * 无历史时打开抽屉后自动弹出生成框
 */
import { computed, ref } from 'vue';

import { useVbenDrawer, useVbenModal } from '@vben/common-ui';
import { Button, Descriptions, Input, Spin, message } from 'ant-design-vue';

import {
  aiGenerateMedicalRecord,
  aiGenerationDetail,
  aiListGenerations,
} from '../api';
import { MEDICAL_RECORD_FIELD_OPTIONS } from '../config/constants';
import TextareaExpandModal from './TextareaExpandModal.vue';
import AiDisclaimerBanner from '#/views/doctor/components/AiDisclaimerBanner.vue';
import { ensureAiFeatureConsent } from '#/views/doctor/utils/aiFeatureGate';
import PrescriptionLoading from '#/components/loading/PrescriptionLoading.vue';
import { getSystemConfigByKeys } from '#/views/system/system-config/api';

/** 常用|我的展示位置（与病历面板一致，供放大弹窗 chips/气泡） */
type MrCommonDisplayMode = 'tags' | 'bubble' | 'both';

/** 本地「正在生成中」占位 id，不与真实 generation_id 冲突 */
const PENDING_GEN_ID = -1;

/** Descriptions 通栏字段 */
const FULL_SPAN_KEYS = new Set([
  'present_illness',
  'tcm_case',
  'treatment_advice',
  'auxiliary_exam',
  'physical_exam',
  'chief_complaint',
]);
/** 预览字段顺序（不含主诉；与后端 MR_OUTPUT_FIELDS 对齐，含医嘱） */
const PREVIEW_FIELDS = [
  { label: '现病史', value: 'present_illness' },
  { label: '舌象', value: 'tongue' },
  { label: '脉象', value: 'pulse' },
  { label: '中医病案', value: 'tcm_case' },
  { label: '中医证候', value: 'tcm_syndrome' },
  { label: '中医疾病', value: 'tcm_disease' },
  { label: '中医治法', value: 'tcm_method' },
  { label: '临床诊断', value: 'diagnosis' },
  { label: '治疗意见', value: 'treatment_advice' },
  { label: '医嘱', value: 'doctor_order' },
  ...MEDICAL_RECORD_FIELD_OPTIONS.filter((f) =>
    [
      'family_history',
      'epidemic_history',
      'past_history',
      'menstrual_history',
      'marital_history',
      'personal_history',
      'allergy_history',
      'physical_exam',
      'auxiliary_exam',
    ].includes(f.value),
  ),
];

/** 生成前可选填（非必填），传给 AI 作上下文；有值则优先保留 */
const GEN_OPTIONAL_FIELDS = [
  { label: '现病史', value: 'present_illness' },
  { label: '既往史', value: 'past_history' },
  { label: '过敏史', value: 'allergy_history' },
  { label: '月经史', value: 'menstrual_history' },
  { label: '家族史', value: 'family_history' },
  { label: '婚育史', value: 'marital_history' },
  { label: '个人史', value: 'personal_history' },
  { label: '体征检查', value: 'physical_exam' },
  { label: '辅助检查', value: 'auxiliary_exam' },
  { label: '舌象', value: 'tongue' },
  { label: '脉象', value: 'pulse' },
];

function emptyGenContext(): Record<string, string> {
  const o: Record<string, string> = {};
  for (const f of GEN_OPTIONAL_FIELDS) o[f.value] = '';
  return o;
}

const emit = defineEmits<{
  (
    e: 'import',
    payload: {
      chief_complaint: string;
      fields: Record<string, string>;
      tcm_ids?: {
        diseases_id?: number | null;
        method_id?: number | null;
        syndrome_id?: number | null;
      } | null;
      /** P4：本次导入来源的 AI 生成记录 ID，保存病历时回传做采纳率统计 */
      generation_id?: number;
    },
  ): void;
  /** 生成弹窗里改字段时即时回写病历面板（与 AI 出方 sync-medical-record 同协议） */
  (e: 'sync-medical-record', payload: Record<string, any>): void;
}>();

const registerId = ref(0);
const storeId = ref(0);
const patientName = ref('');
const patientSex = ref(0);
const patientAge = ref(0);
const chiefComplaint = ref('');
/** 生成弹窗可选上下文字段 */
const genContext = ref<Record<string, string>>(emptyGenContext());
const histLoading = ref(false);
const generating = ref(false);
const detailLoading = ref(false);
const historyList = ref<any[]>([]);
const activeId = ref(0);
const previewFields = ref<Record<string, string>>({});
/** AI 返回的开方旧字段 id（导入时一并交给病历面板） */
const previewTcmIds = ref<{
  diseases_id?: number | null;
  method_id?: number | null;
  syndrome_id?: number | null;
} | null>(null);
const previewChief = ref('');
/** 最近一次生成耗时（毫秒） */
const lastDurationMs = ref(0);
/** 醒目提示文案（系统配置 / 门闸下发） */
const disclaimerText = ref('');
/**
 * P2 病历质量提示（后端 quality_flags）：
 * 必填空缺/主诉-诊断不自洽/辨证链路不完整，规则级提示医生人工核对
 */
const qualityFlags = ref<
  Array<{ field?: string; level: string; message: string; type: string }>
>([]);

/** 解析后端 quality_flags 结构（结构异常时静默为空，不影响预览） */
function applyQualityFlags(quality: any) {
  const flags = Array.isArray(quality?.flags) ? quality.flags : [];
  qualityFlags.value = flags
    .map((f: any) => ({
      type: String(f?.type || ''),
      level: String(f?.level || 'info'),
      field: String(f?.field || ''),
      message: String(f?.message || '').trim(),
    }))
    .filter((f: any) => f.message);
}

/** 质量提示分级样式（warning橙/info灰，主题变量适配暗色） */
function qualityLevelClass(level: string) {
  if (level === 'error') return 'text-red-500';
  if (level === 'warning') return 'text-orange-500';
  return 'text-muted-foreground';
}

const sexLabel = computed(() => {
  const s = Number(patientSex.value);
  if (s === 1) return '男';
  if (s === 2) return '女';
  return '未知';
});

const previewRows = computed(() =>
  PREVIEW_FIELDS.map((f) => ({
    label: f.label,
    value: String(previewFields.value[f.value] || '').trim(),
    code: f.value,
  })).filter((r) => r.value !== ''),
);

/**
 * 二级「生成病历」弹窗行：主诉始终展示 + 选填字段（空也展示，可点改）
 * UI 与 AI 出方 GenModal 一致：Descriptions 浏览态 / 点击进入 TextArea
 */
const genPreviewRows = computed(() => {
  const rows: Array<{ key: string; label: string }> = [
    { key: 'chief_complaint', label: '主诉' },
  ];
  for (const f of GEN_OPTIONAL_FIELDS) {
    rows.push({ key: f.value, label: f.label });
  }
  return rows;
});

/** 二级弹窗：当前正在编辑的字段 key，空表示浏览态 */
const editingKey = ref('');
/** 单击延迟定时器：与双击放大区分开，避免双击先误进行内编辑 */
let genFieldClickTimer: ReturnType<typeof setTimeout> | null = null;
const commonDisplayMode = ref<MrCommonDisplayMode>('tags');
const showCommonTags = computed(
  () => commonDisplayMode.value === 'tags' || commonDisplayMode.value === 'both',
);
const showCommonInBubble = computed(
  () =>
    commonDisplayMode.value === 'bubble' || commonDisplayMode.value === 'both',
);

const [Drawer, drawerApi] = useVbenDrawer({
  title: 'AI写病历',
  class: 'w-[860px]',
  footer: false,
  showCancelButton: false,
  showConfirmButton: false,
  contentClass: '!flex !flex-col !overflow-hidden',
  async onOpenChange(isOpen) {
    if (!isOpen) {
      resetState();
      return;
    }
    const data = drawerApi.getData<{
      registerId: number;
      storeId?: number;
      patientName?: string;
      patientSex?: number;
      patientAge?: number;
      chiefComplaint?: string;
      medicalRecord?: Record<string, any>;
    }>();
    registerId.value = Number(data?.registerId || 0);
    storeId.value = Number(data?.storeId || 0);
    patientName.value = String(data?.patientName || '');
    patientSex.value = Number(data?.patientSex || 0);
    patientAge.value = Number(data?.patientAge || 0);
    chiefComplaint.value = String(data?.chiefComplaint || '');
    // 从当前病历表单预填可选字段
    const nextCtx = emptyGenContext();
    const snap = data?.medicalRecord || {};
    for (const f of GEN_OPTIONAL_FIELDS) {
      nextCtx[f.value] = String(snap[f.value] ?? '').trim();
    }
    genContext.value = nextCtx;
    previewFields.value = {};
    previewChief.value = '';
    activeId.value = 0;
    try {
      const gate = await ensureAiFeatureConsent({
        featureCode: 'ai_medical_record',
        storeId: storeId.value || undefined,
      });
      if (!gate) {
        drawerApi.close();
        return;
      }
      disclaimerText.value = gate.disclaimer_text || '';
    } catch (e: any) {
      message.error(e?.message || e?.msg || '无法校验 AI 使用规范');
      drawerApi.close();
      return;
    }
    void loadCommonDisplayMode();
    void bootstrapHistory();
  },
});

const [GenModal, genModalApi] = useVbenModal({
  title: '生成病历',
  // 与 AI 出方生成弹窗同宽，便于选填字段双列展示
  class: 'w-[920px]',
  confirmText: '开始生成',
  cancelText: '取消',
  onConfirm: async () => confirmGenerateAndClose(),
});

/** 与病历面板同一套双击放大编辑 */
const [ExpandModal, expandModalApi] = useVbenModal({
  connectedComponent: TextareaExpandModal,
});

function resetState() {
  histLoading.value = false;
  generating.value = false;
  detailLoading.value = false;
  historyList.value = [];
  activeId.value = 0;
  previewFields.value = {};
  previewChief.value = '';
  lastDurationMs.value = 0;
  chiefComplaint.value = '';
  genContext.value = emptyGenContext();
  disclaimerText.value = '';
  editingKey.value = '';
  if (genFieldClickTimer) {
    clearTimeout(genFieldClickTimer);
    genFieldClickTimer = null;
  }
  expandModalApi.close();
  genModalApi.close();
}

/** 拉取常用词条展示模式，放大弹窗 chips/气泡与病历页一致 */
async function loadCommonDisplayMode() {
  try {
    const res = await getSystemConfigByKeys(['mr_common_display_mode']);
    const mode = String(
      res?.mr_common_display_mode ?? res?.data?.mr_common_display_mode ?? 'tags',
    ) as MrCommonDisplayMode;
    if (mode === 'tags' || mode === 'bubble' || mode === 'both') {
      commonDisplayMode.value = mode;
    }
  } catch {
    commonDisplayMode.value = 'tags';
  }
}

function formatTime(ts: number) {
  const n = Number(ts || 0);
  if (!n) return '—';
  const d = new Date(n * 1000);
  const pad = (x: number) => (x < 10 ? `0${x}` : `${x}`);
  return `${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${pad(d.getHours())}:${pad(d.getMinutes())}`;
}

/** 毫秒转可读耗时（850ms / 1.2s） */
function formatDurationMs(ms: number | undefined | null) {
  const n = Number(ms || 0);
  if (!n) return '';
  if (n < 1000) return `${Math.round(n)}ms`;
  const sec = n / 1000;
  return sec >= 10 ? `${Math.round(sec)}s` : `${sec.toFixed(1)}s`;
}

async function loadHistory() {
  histLoading.value = true;
  try {
    const list = await aiListGenerations({
      register_id: registerId.value,
      scene: 'medical_record',
      limit: 30,
    });
    historyList.value = Array.isArray(list) ? list : [];
  } catch (e: any) {
    historyList.value = [];
    message.error(e?.message || e?.msg || '加载历史失败');
  } finally {
    histLoading.value = false;
  }
}

/** 有历史选最新；无历史自动打开生成框 */
async function bootstrapHistory() {
  if (!registerId.value) return;
  await loadHistory();
  if (historyList.value.length) {
    await onSelectHistory(historyList.value[0]);
  } else {
    openGenerateModal();
  }
}

function openGenerateModal() {
  editingKey.value = '';
  genModalApi.open();
}

/** 点字段进入行内编辑（与 AI 出方二级弹窗同一交互） */
function startEdit(key: string) {
  editingKey.value = key;
}

function fieldValue(key: string) {
  if (key === 'chief_complaint') return chiefComplaint.value;
  return String(genContext.value?.[key] ?? '');
}

/**
 * 生成弹窗字段编辑：主诉写 chiefComplaint，其余写 genContext
 * 同时 emit 回写病历面板，避免只改弹窗本地态、父页表单仍是旧值
 */
function onFieldInput(key: string, val: string) {
  if (key === 'chief_complaint') {
    chiefComplaint.value = val;
  } else {
    genContext.value = {
      ...genContext.value,
      [key]: val,
    };
  }
  emit('sync-medical-record', { [key]: val });
}

function endEdit() {
  editingKey.value = '';
}

/**
 * 单击延迟进项内编辑：若随后是双击则取消，改为打开放大弹窗
 * （否则双击的第一次 click 会先切到 TextArea，导致 dblclick 丢事件）
 */
function onGenFieldClick(key: string) {
  if (genFieldClickTimer) clearTimeout(genFieldClickTimer);
  genFieldClickTimer = setTimeout(() => {
    genFieldClickTimer = null;
    startEdit(key);
  }, 250);
}

function onGenFieldDblClick(key: string, label: string) {
  if (genFieldClickTimer) {
    clearTimeout(genFieldClickTimer);
    genFieldClickTimer = null;
  }
  openGenFieldExpand(key, label);
}

/**
 * 行内 TextArea 用 mousedown.detail===2 捕获双击
 * 为什么不用 dblclick：blur 会先卸载 TextArea，导致 dblclick 丢事件
 */
function onGenTextareaMouseDown(e: MouseEvent, key: string, label: string) {
  if (e.detail === 2) {
    e.preventDefault();
    openGenFieldExpand(key, label);
  }
}

/**
 * 双击字段：打开与病历页同一套 TextareaExpandModal（词条搜索 + 常用）
 * joinMode/source 规则对齐 MedicalRecordPanel.openFieldExpand
 */
function openGenFieldExpand(key: string, label: string) {
  editingKey.value = '';
  const joinMode =
    key === 'tongue' || key === 'pulse' ? 'replace' : 'newline';
  expandModalApi.setData({
    title: label,
    value: fieldValue(key) || '',
    onConfirm: (v: string) => onFieldInput(key, v),
    storeId: storeId.value,
    source: 'entry',
    fieldCode: key,
    showChips: showCommonTags.value,
    showCommonInBubble: showCommonInBubble.value,
    joinMode,
  });
  expandModalApi.open();
}

async function onSelectHistory(row: any) {
  if (!row?.id || Number(row.id) === PENDING_GEN_ID || row._pending) return;
  activeId.value = Number(row.id);
  detailLoading.value = true;
  try {
    const data = await aiGenerationDetail({ id: Number(row.id) });
    const fields = (data?.fields || {}) as Record<string, string>;
    previewFields.value = { ...fields };
    previewTcmIds.value = (data?.tcm_ids || null) as typeof previewTcmIds.value;
    applyQualityFlags(data?.quality_flags || null);
    const snap = data?.input_snapshot || {};
    previewChief.value = String(
      snap.chief_complaint || chiefComplaint.value || '',
    ).trim();
    lastDurationMs.value = Number(row.duration_ms || 0);
  } catch (e: any) {
    previewFields.value = {};
    previewTcmIds.value = null;
    previewChief.value = '';
    qualityFlags.value = [];
    message.error(e?.message || e?.msg || '加载详情失败');
  } finally {
    detailLoading.value = false;
  }
}

/** 先关弹窗，回抽屉等待生成 */
async function confirmGenerateAndClose(): Promise<boolean> {
  if (generating.value) return false;
  const chief = chiefComplaint.value.trim();
  if (!chief) {
    message.warning('请先填写主诉后再生成');
    return false;
  }
  if (!registerId.value) {
    message.warning('挂号无效');
    return false;
  }
  genModalApi.close();
  void runGenerateInDrawer(chief);
  return true;
}

/**
 * 开始生成：取消旧选中、清空预览，历史顶部插入「正在生成中」占位
 */
function beginGeneratingPlaceholder() {
  activeId.value = PENDING_GEN_ID;
  previewFields.value = {};
  previewTcmIds.value = null;
  qualityFlags.value = [];
  lastDurationMs.value = 0;
  const rest = (historyList.value || []).filter(
    (r) => Number(r?.id) !== PENDING_GEN_ID && !r?._pending,
  );
  historyList.value = [
    {
      id: PENDING_GEN_ID,
      name: '正在生成中…',
      created_at: Math.floor(Date.now() / 1000),
      _pending: true,
    },
    ...rest,
  ];
}

function endGeneratingPlaceholder() {
  historyList.value = (historyList.value || []).filter(
    (r) => Number(r?.id) !== PENDING_GEN_ID && !r?._pending,
  );
  if (Number(activeId.value) === PENDING_GEN_ID) {
    activeId.value = 0;
  }
}

async function runGenerateInDrawer(chief: string) {
  beginGeneratingPlaceholder();
  generating.value = true;
  previewChief.value = chief;
  try {
    const data = await aiGenerateMedicalRecord({
      register_id: registerId.value,
      store_id: storeId.value || undefined,
      chief_complaint: chief,
      medical_record: { ...genContext.value },
    });
    const durationText = formatDurationMs(data?.duration_ms);
    lastDurationMs.value = Number(data?.duration_ms || 0);
    // 业务软失败：HTTP 成功但 ok=false，警告提示而非 error
    if (data?.ok === false) {
      endGeneratingPlaceholder();
      previewFields.value = {};
      previewTcmIds.value = null;
      if (data?.generation_id) {
        await loadHistory();
        activeId.value = Number(data.generation_id);
      }
      message.warning(String(data?.message || '生成未成功'));
      return;
    }
    previewFields.value = (data?.fields || {}) as Record<string, string>;
    previewTcmIds.value = (data?.tcm_ids || null) as typeof previewTcmIds.value;
    applyQualityFlags(data?.quality_flags || null);
    await loadHistory();
    activeId.value = Number(data?.generation_id || 0);
    message.success(
      durationText ? `已生成（耗时 ${durationText}）` : '已生成，请预览后确认导入',
    );
  } catch (e: any) {
    endGeneratingPlaceholder();
    previewFields.value = {};
    previewTcmIds.value = null;
    qualityFlags.value = [];
    message.error(e?.message || e?.msg || 'AI写病历失败');
  } finally {
    generating.value = false;
  }
}

function onConfirmImport() {
  if (!Object.keys(previewFields.value || {}).length && !previewChief.value) {
    message.warning('暂无可导入内容');
    return;
  }
  emit('import', {
    chief_complaint: String(previewChief.value || chiefComplaint.value || '').trim(),
    fields: { ...previewFields.value },
    tcm_ids: previewTcmIds.value || null,
    // P4：带上生成记录 ID，病历保存时透传后端做采纳率/修改率统计
    generation_id: activeId.value > 0 ? activeId.value : undefined,
  });
  drawerApi.close();
}

defineExpose({
  open(payload: {
    registerId: number;
    storeId?: number;
    patientName?: string;
    patientSex?: number;
    patientAge?: number;
    chiefComplaint?: string;
    medicalRecord?: Record<string, any>;
  }) {
    drawerApi.setData(payload);
    drawerApi.open();
  },
});
</script>

<template>
  <Drawer>
    <div class="flex min-h-0 flex-1 flex-col gap-2 overflow-hidden text-foreground">
      <div class="shrink-0 text-sm text-muted-foreground">
        {{ patientName || '—' }} · {{ sexLabel }} · {{ patientAge || '—' }}岁
      </div>
      <AiDisclaimerBanner class="shrink-0" :text="disclaimerText" />
      <!-- P2 病历质量提示：规则级检查（必填空缺/自洽性/辨证链路），医生人工核对 -->
      <div
        v-if="qualityFlags.length && !generating"
        class="shrink-0 rounded-lg border border-orange-500/35 bg-orange-500/5 px-3 py-2 text-xs"
      >
        <div class="mb-1 font-medium text-orange-500">质量提示（请人工核对）</div>
        <div v-for="(f, i) in qualityFlags" :key="i" class="leading-5">
          <span class="font-medium" :class="qualityLevelClass(f.level)">·</span>
          <span :class="f.level === 'info' ? 'text-muted-foreground' : ''">
            {{ f.message }}
          </span>
        </div>
      </div>
      <div class="flex min-h-0 flex-1 gap-3 overflow-hidden">
        <div class="w-44 shrink-0 overflow-y-auto border-r border-border pr-2">
          <div class="mb-2 text-sm font-medium">历史记录</div>
          <div v-if="histLoading" class="text-xs text-muted-foreground">加载中…</div>
          <div v-else-if="!historyList.length" class="text-xs text-muted-foreground">
            暂无记录，可点击下方「生成病历」
          </div>
          <div
            v-for="row in historyList"
            :key="row.id"
            class="mb-1 cursor-pointer rounded-md px-2 py-1.5 text-xs transition-colors hover:bg-accent"
            :class="{
              'bg-primary/10 ring-1 ring-primary/20': activeId === Number(row.id),
              'cursor-default border border-dashed border-primary/40 bg-primary/5':
                Number(row.id) === PENDING_GEN_ID || row._pending,
            }"
            @click="onSelectHistory(row)"
          >
            <div class="truncate font-medium">
              {{
                Number(row.id) === PENDING_GEN_ID || row._pending
                  ? '正在生成中…'
                  : row.name || `病历 #${row.id}`
              }}
            </div>
            <div class="mt-0.5 text-muted-foreground">
              <template v-if="Number(row.id) === PENDING_GEN_ID || row._pending">
                请稍候，右侧为生成进度
              </template>
              <template v-else>
                {{ formatTime(row.created_at) }}
                <span v-if="row.duration_ms"> · {{ formatDurationMs(row.duration_ms) }}</span>
              </template>
            </div>
          </div>
        </div>
        <div class="min-h-0 min-w-0 flex-1 overflow-y-auto pl-1 pb-2">
          <!-- AI 专属动画：仅真正调用生成接口时展示，历史详情加载用普通 Spin -->
          <div
            v-if="generating"
            class="flex h-full min-h-[260px] items-center justify-center"
          >
            <PrescriptionLoading
              type="medical_record"
              text="AI正在生成病历"
              class="h-[280px] w-full max-w-[420px]"
            />
          </div>
          <div
            v-else-if="detailLoading"
            class="flex h-full min-h-[200px] flex-col items-center justify-center gap-2 text-muted-foreground"
          >
            <Spin />
            <span class="text-sm">加载历史病历…</span>
          </div>
          <template v-else>
            <div
              v-if="!previewRows.length && !previewChief && !lastDurationMs"
              class="py-8 text-center text-muted-foreground"
            >
              请选择左侧历史，或点击「生成病历」
            </div>
            <div
              v-else-if="!previewRows.length && !previewChief && lastDurationMs"
              class="py-8 text-center text-muted-foreground"
            >
              本次生成未产出病历内容
              <span v-if="formatDurationMs(lastDurationMs)">
                （耗时 {{ formatDurationMs(lastDurationMs) }}）
              </span>
            </div>
            <template v-else>
              <Descriptions
                v-if="previewChief || previewRows.length"
                :column="2"
                bordered
                size="small"
                class="ai-mr-preview-desc"
              >
                <Descriptions.Item
                  v-if="previewChief"
                  label="主诉"
                  :span="2"
                >
                  <div class="max-h-20 overflow-y-auto whitespace-pre-wrap leading-relaxed">
                    {{ previewChief }}
                  </div>
                </Descriptions.Item>
                <Descriptions.Item
                  v-if="lastDurationMs"
                  label="生成耗时"
                >
                  {{ formatDurationMs(lastDurationMs) }}
                </Descriptions.Item>
                <Descriptions.Item
                  v-for="row in previewRows"
                  :key="row.code"
                  :label="row.label"
                  :span="FULL_SPAN_KEYS.has(row.code) ? 2 : 1"
                >
                  <div class="max-h-20 overflow-y-auto whitespace-pre-wrap leading-relaxed">
                    {{ row.value }}
                  </div>
                </Descriptions.Item>
              </Descriptions>
              <div
                v-else
                class="py-4 text-center text-xs text-muted-foreground"
              >
                暂无生成字段
              </div>
            </template>
          </template>
        </div>
      </div>
      <div class="flex shrink-0 justify-end gap-2 border-t border-border pt-3">
        <Button @click="drawerApi.close()">关闭</Button>
        <Button type="default" @click="openGenerateModal">生成病历</Button>
        <Button
          type="primary"
          :disabled="generating || detailLoading || (!previewRows.length && !previewChief)"
          @click="onConfirmImport"
        >
          确认导入
        </Button>
      </div>
    </div>
  </Drawer>

  <!-- 二级：与 AI 出方一致 — Descriptions 浏览态 + 点击编辑；双击同病历页放大 -->
  <GenModal>
    <div class="space-y-2 text-sm text-foreground">
      <AiDisclaimerBanner :text="disclaimerText" />
      <div class="text-xs text-muted-foreground">
        {{ patientName || '—' }} · {{ sexLabel }} · {{ patientAge || '—' }}岁 ·
        主诉必填；单击编辑，双击放大（同病历页）；选填有内容会作为 AI 参考
      </div>
      <div class="max-h-[58vh] overflow-y-auto">
        <Descriptions
          :column="2"
          bordered
          size="small"
          class="ai-mr-gen-desc"
        >
          <Descriptions.Item
            v-for="row in genPreviewRows"
            :key="row.key"
            :label="row.label"
            :span="FULL_SPAN_KEYS.has(row.key) ? 2 : 1"
          >
            <Input.TextArea
              v-if="editingKey === row.key"
              :value="fieldValue(row.key)"
              :rows="row.key === 'chief_complaint' ? 3 : 2"
              autofocus
              :placeholder="`${row.label}（双击放大）`"
              @update:value="(v) => onFieldInput(row.key, String(v ?? ''))"
              @blur="endEdit"
              @mousedown="(e) => onGenTextareaMouseDown(e, row.key, row.label)"
            />
            <div
              v-else
              class="max-h-24 cursor-text overflow-y-auto whitespace-pre-wrap leading-relaxed"
              title="单击编辑，双击放大"
              @click="onGenFieldClick(row.key)"
              @dblclick.stop.prevent="onGenFieldDblClick(row.key, row.label)"
            >
              {{ fieldValue(row.key) || '（空，单击填写 / 双击放大）' }}
            </div>
          </Descriptions.Item>
        </Descriptions>
      </div>
    </div>
  </GenModal>
  <ExpandModal />
</template>

<style scoped>
/* label 宽与 AI 出方 .ai-rx-gen-desc 对齐 */
.ai-mr-preview-desc :deep(.ant-descriptions-item-label),
.ai-mr-gen-desc :deep(.ant-descriptions-item-label) {
  width: 110px;
  white-space: nowrap;
}
.ai-mr-preview-desc :deep(.ant-descriptions-item-content),
.ai-mr-gen-desc :deep(.ant-descriptions-item-content) {
  font-size: 12px;
}
</style>
