<script lang="ts" setup>
/**
 * 缺失药处理面板
 * - 添加药材：打开中药管理「新增中药」模态框
 * - 挂别名：ChineseDrugNameBubble 选目标药
 * - 替换已有：可 1→N（错误合并名拆多味）→ 预览勾选金方 → 确认
 */
import { computed, ref, watch } from 'vue';

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

import { Button, Modal, Space, Table, Tag, message } from 'ant-design-vue';

import {
  ChineseDrugNameBubble,
  type ChineseDrugBubbleItem,
} from '#/components/chinese-drug-name-bubble';
import ChinaMedicineFormModal from '#/views/business/product/china-medicine/components/modal.vue';

import {
  bindMissingAsAlias,
  getFormulasByDrugName,
  replaceMissingWithDrug,
  resolveMissingByName,
} from '../api';

/** 替换目标行：只选药名，克数各方继承原味（不在此填写） */
interface ReplaceTargetRow {
  key: string;
  displayName: string;
  drugId: number;
}

const props = defineProps<{
  open: boolean;
  missingId?: number;
  drugName: string;
  /** 药方设置场景：预览时默认勾选当前金方 */
  formulaId?: number;
}>();

const emit = defineEmits<{
  (e: 'update:open', v: boolean): void;
  (e: 'done'): void;
}>();

const userStore = useUserStore();
const searchStoreId = Number(userStore.userInfo?.store_id || 0);

const step = ref<'choose' | 'alias' | 'replace'>('choose');
const submitting = ref(false);
const selectedDrug = ref<ChineseDrugBubbleItem | null>(null);
const selectedDisplayName = ref('');

/** 替换目标列表（可多味） */
const replaceTargets = ref<ReplaceTargetRow[]>([]);
/** 当前正在搜索选择的那一行 */
const activeReplaceKey = ref('');

/** 替换预览：含该药名的金方 */
const previewLoading = ref(false);
const previewFormulas = ref<any[]>([]);
const selectedFormulaIds = ref<number[]>([]);

const previewColumns = [
  { title: 'ID', dataIndex: 'id', key: 'id', width: 60 },
  { title: '药方名字', dataIndex: 'name', key: 'name', width: 120, ellipsis: true },
  { title: '条文', dataIndex: 'clause_number', key: 'clause_number', width: 70 },
  { title: '原克数', dataIndex: 'match_dose_text', key: 'match_dose_text', width: 110 },
  { title: '拆分后预览', key: 'split_preview', ellipsis: true },
  { title: '标记', key: 'flags', width: 110 },
];

const selectedFormulaCount = computed(() => selectedFormulaIds.value.length);
const validReplaceTargets = computed(() =>
  replaceTargets.value.filter((r) => r.drugId > 0 && r.displayName),
);
const replaceTargetNamesText = computed(() =>
  validReplaceTargets.value.map((r) => r.displayName).join('、'),
);

/**
 * 按该方原味克数生成拆分预览文案（各方克数可能不同，统一继承本方原味）
 */
function buildSplitPreview(record: {
  match_dose_text?: string;
  match_dose?: string;
  match_unit?: string;
  match_ancient_dose?: string;
}): string {
  const names = validReplaceTargets.value.map((r) => r.displayName);
  if (!names.length) return '请先选择目标药材';
  const doseText =
    String(record?.match_dose_text || '').trim() ||
    (() => {
      const d = String(record?.match_dose || '').trim();
      const u = String(record?.match_unit || 'g').trim() || 'g';
      const a = String(record?.match_ancient_dose || '').trim();
      let t = d ? `${d}${u}` : '';
      if (a) t = t ? `${t}（${a}）` : a;
      return t;
    })();
  return names
    .map((n) => (doseText ? `${n} ${doseText}` : n))
    .join('、');
}

const [ChinaMedicineModal, chinaMedicineModalApi] = useVbenModal({
  connectedComponent: ChinaMedicineFormModal,
});

function newReplaceRow(): ReplaceTargetRow {
  return {
    key: `rt-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`,
    displayName: '',
    drugId: 0,
  };
}

watch(
  () => props.open,
  (v) => {
    if (v) {
      step.value = 'choose';
      selectedDrug.value = null;
      selectedDisplayName.value = '';
      replaceTargets.value = [newReplaceRow()];
      activeReplaceKey.value = replaceTargets.value[0]?.key || '';
      previewFormulas.value = [];
      selectedFormulaIds.value = [];
    }
  },
);

function close() {
  emit('update:open', false);
}

function buildBasePayload() {
  const payload: { id?: number; drug_name?: string } = {
    drug_name: props.drugName,
  };
  if (props.missingId && props.missingId > 0) {
    payload.id = props.missingId;
  }
  return payload;
}

/**
 * 打开中药管理新增弹窗
 */
function openCreateMedicineModal() {
  if (!props.drugName) {
    message.warning('药名为空');
    return;
  }
  const resolvePayload = buildBasePayload();
  const missingName = props.drugName;
  close();
  chinaMedicineModalApi.setData({
    update: false,
    values: {
      drug_name: missingName,
      drug_alias: missingName,
      drug_number: `GF${Date.now().toString().slice(-10)}`,
      status: 1,
      time_id: 1,
      type_id: 1,
      unit_id: 1,
      frequency_id: 1,
    },
    onSuccess: async () => {
      try {
        await resolveMissingByName({
          ...resolvePayload,
          remark: '已通过中药管理新增',
        });
        message.success(`缺失药「${missingName}」已标记为已解决`);
        emit('done');
      } catch (e: any) {
        message.error(e?.message || '标记已解决失败，请在缺失药品里重新校验');
      }
    },
  });
  chinaMedicineModalApi.open();
}

function onSelectDrug(item: ChineseDrugBubbleItem) {
  selectedDrug.value = item;
  selectedDisplayName.value = String(
    item?.drug?.drug_name || item?.drug_name || '',
  ).trim();
}

function resolveTargetDrugId(): number {
  const item = selectedDrug.value;
  if (!item) return 0;
  return Number(item.drug_id || item.drug?.id || 0);
}

/**
 * 替换行选中药材（必须带 key，避免多行时写错位）
 * 克数不在此填写：确认后由后端按各方原味 dose 继承
 */
function onSelectReplaceTarget(key: string, item: ChineseDrugBubbleItem) {
  activeReplaceKey.value = key;
  const row = replaceTargets.value.find((r) => r.key === key);
  if (!row) return;
  const drugId = Number(item.drug_id || item.drug?.id || 0);
  const displayName = String(
    item?.drug?.drug_name || item?.drug_name || '',
  ).trim();
  if (!drugId || !displayName) {
    message.warning('未识别到有效药材');
    return;
  }
  // 同一列表禁止重复选同一味
  const dup = replaceTargets.value.some(
    (r) => r.key !== key && r.drugId === drugId,
  );
  if (dup) {
    message.warning(`「${displayName}」已在目标列表中`);
    return;
  }
  row.drugId = drugId;
  row.displayName = displayName;
}

function focusReplaceRow(key: string) {
  activeReplaceKey.value = key;
}

function addReplaceRow() {
  const row = newReplaceRow();
  replaceTargets.value.push(row);
  activeReplaceKey.value = row.key;
}

function removeReplaceRow(key: string) {
  if (replaceTargets.value.length <= 1) {
    // 至少保留一行空位
    replaceTargets.value = [newReplaceRow()];
    activeReplaceKey.value = replaceTargets.value[0]!.key;
    return;
  }
  replaceTargets.value = replaceTargets.value.filter((r) => r.key !== key);
  if (!replaceTargets.value.some((r) => r.key === activeReplaceKey.value)) {
    activeReplaceKey.value = replaceTargets.value[0]?.key || '';
  }
}

/**
 * 加载含该缺失药名的金方预览，并默认勾选
 * - 有 formulaId：默认只勾当前方（可再加选）
 * - 否则：默认全选
 */
async function loadFormulaPreview() {
  if (!props.drugName) {
    previewFormulas.value = [];
    selectedFormulaIds.value = [];
    return;
  }
  previewLoading.value = true;
  try {
    const list = await getFormulasByDrugName(props.drugName);
    previewFormulas.value = Array.isArray(list) ? list : [];
    const allIds = previewFormulas.value.map((r) => Number(r.id)).filter((id) => id > 0);
    if (props.formulaId && props.formulaId > 0) {
      selectedFormulaIds.value = allIds.includes(props.formulaId)
        ? [props.formulaId]
        : allIds.length
          ? [allIds[0]!]
          : [];
    } else {
      selectedFormulaIds.value = allIds;
    }
  } catch (e: any) {
    previewFormulas.value = [];
    selectedFormulaIds.value = [];
    message.error(e?.message || '加载受影响金方失败');
  } finally {
    previewLoading.value = false;
  }
}

async function goPick(next: 'alias' | 'replace') {
  step.value = next;
  selectedDrug.value = null;
  selectedDisplayName.value = '';
  if (next === 'replace') {
    replaceTargets.value = [newReplaceRow()];
    activeReplaceKey.value = replaceTargets.value[0]!.key;
    await loadFormulaPreview();
  } else {
    previewFormulas.value = [];
    selectedFormulaIds.value = [];
  }
}

function onFormulaSelectChange(keys: (string | number)[]) {
  selectedFormulaIds.value = keys.map((k) => Number(k)).filter((id) => id > 0);
}

function selectAllFormulas() {
  selectedFormulaIds.value = previewFormulas.value
    .map((r) => Number(r.id))
    .filter((id) => id > 0);
}

function clearFormulaSelection() {
  selectedFormulaIds.value = [];
}

async function confirmAlias() {
  const targetDrugId = resolveTargetDrugId();
  if (!targetDrugId) {
    message.warning('请先搜索并选择目标药材');
    return;
  }
  submitting.value = true;
  try {
    await bindMissingAsAlias({
      ...buildBasePayload(),
      target_drug_id: targetDrugId,
    });
    message.success(`「${props.drugName}」已写入别名表`);
    emit('done');
    close();
  } catch (e: any) {
    message.error(e?.message || '写入别名失败');
  } finally {
    submitting.value = false;
  }
}

/**
 * 确认替换：支持多味拆分，只改预览勾选的金方
 */
async function confirmReplace() {
  const targets = validReplaceTargets.value;
  if (!targets.length) {
    message.warning('请至少选择一味目标药材');
    return;
  }
  if (!selectedFormulaIds.value.length) {
    message.warning('请至少勾选一个要修改的金方');
    return;
  }
  submitting.value = true;
  try {
    // 不传 dose：后端按各方原味克数继承到拆出的每一味
    const res = await replaceMissingWithDrug({
      ...buildBasePayload(),
      formula_ids: selectedFormulaIds.value,
      targets: targets.map((t) => ({
        target_drug_id: t.drugId,
      })),
    });
    const names =
      Array.isArray(res?.new_names) && res.new_names.length
        ? res.new_names.join('、')
        : res?.new_name || replaceTargetNamesText.value;
    const tip =
      targets.length > 1
        ? `已将「${res?.old_name || props.drugName}」拆分为「${names}」（共 ${Number(res?.formula_count || 0)} 个金方）`
        : `已将「${res?.old_name || props.drugName}」替换为「${names}」（共 ${Number(res?.formula_count || 0)} 个金方，旧名已保留）`;
    message.success(tip);
    emit('done');
    close();
  } catch (e: any) {
    message.error(e?.message || '替换失败');
  } finally {
    submitting.value = false;
  }
}
</script>
<template>
  <ChinaMedicineModal />
  <Modal
    :open="open"
    :title="`处理缺失药：${drugName || ''}`"
    :footer="null"
    destroy-on-close
    :width="step === 'replace' ? 960 : 520"
    @cancel="close"
  >
    <div v-if="step === 'choose'" class="gf-resolve-choose">
      <p class="gf-resolve-tip">
        该药名在药品库中不存在，请选择处理方式：
      </p>
      <Space direction="vertical" style="width: 100%">
        <Button type="primary" block @click="openCreateMedicineModal">
          添加药材（打开中药管理新增）
        </Button>
        <Button block @click="goPick('alias')">
          放入药材别名表（挂到已有药，不改金方药名）
        </Button>
        <Button block @click="goPick('replace')">
          替换为已有药材（可拆成多味，预览勾选金方后确认）
        </Button>
      </Space>
    </div>
    <div v-else-if="step === 'alias'" class="gf-resolve-alias">
      <p class="gf-resolve-tip">
        将「{{ drugName }}」挂到下方目标药材的别名表（金方组成里的药名不变）：
      </p>
      <div class="gf-resolve-search">
        <span class="gf-resolve-search-label">搜索中药</span>
        <ChineseDrugNameBubble
          :display-name="selectedDisplayName"
          :type="1"
          :store-id="searchStoreId"
          placeholder="输入药名搜索"
          @select="onSelectDrug"
        />
      </div>
      <p v-if="selectedDisplayName" class="gf-resolve-selected">
        已选：{{ selectedDisplayName }}
        <span v-if="resolveTargetDrugId()">（ID {{ resolveTargetDrugId() }}）</span>
      </p>
      <Space>
        <Button @click="step = 'choose'">返回</Button>
        <Button type="primary" :loading="submitting" @click="confirmAlias">
          确认挂别名
        </Button>
      </Space>
    </div>
    <div v-else class="gf-resolve-replace">
      <p class="gf-resolve-tip">
        1）添加目标药材（可多味）；2）下方预览各方原克数，拆分后每味都继承该方原味克数（各方可能不同，无需手填）；3）勾选金方后确认。
      </p>
      <div class="gf-replace-targets">
        <div
          v-for="(row, idx) in replaceTargets"
          :key="row.key"
          class="gf-replace-row"
          :class="{ 'is-active': activeReplaceKey === row.key }"
          @click="focusReplaceRow(row.key)"
        >
          <span class="gf-replace-idx">{{ idx + 1 }}</span>
          <div class="gf-replace-search" @mousedown="focusReplaceRow(row.key)">
            <ChineseDrugNameBubble
              :display-name="row.displayName"
              :type="1"
              :store-id="searchStoreId"
              placeholder="搜索并选择目标药"
              @select="(item) => onSelectReplaceTarget(row.key, item)"
            />
          </div>
          <Button
            type="link"
            danger
            size="small"
            @click.stop="removeReplaceRow(row.key)"
          >
            删除
          </Button>
        </div>
        <Button type="dashed" block class="gf-replace-add" @click="addReplaceRow">
          + 再加一味目标药
        </Button>
        <p v-if="validReplaceTargets.length" class="gf-resolve-selected">
          将拆分为：{{ replaceTargetNamesText }}（共 {{ validReplaceTargets.length }} 味，克数各方继承原味）
        </p>
      </div>
      <div class="gf-preview-toolbar">
        <span class="gf-preview-title">
          受影响金方预览（已勾选 {{ selectedFormulaCount }} / {{ previewFormulas.length }}）
        </span>
        <Space>
          <Button size="small" :loading="previewLoading" @click="loadFormulaPreview">
            刷新
          </Button>
          <Button size="small" @click="selectAllFormulas">全选</Button>
          <Button size="small" @click="clearFormulaSelection">清空</Button>
        </Space>
      </div>
      <Table
        size="small"
        bordered
        row-key="id"
        :loading="previewLoading"
        :columns="previewColumns"
        :data-source="previewFormulas"
        :pagination="previewFormulas.length > 8 ? { pageSize: 8 } : false"
        :row-selection="{
          selectedRowKeys: selectedFormulaIds,
          onChange: onFormulaSelectChange,
        }"
        class="gf-preview-table"
      >
        <template #bodyCell="{ column, record }">
          <template v-if="column.key === 'match_dose_text'">
            {{ record.match_dose_text || '—' }}
          </template>
          <template v-else-if="column.key === 'split_preview'">
            <span class="gf-split-preview">{{ buildSplitPreview(record) }}</span>
          </template>
          <template v-else-if="column.key === 'flags'">
            <Tag v-if="record.is_abnormal === 1" color="error">异常</Tag>
            <Tag v-if="record.has_unmatched === 1" color="warning">未匹配</Tag>
            <Tag
              v-if="formulaId && Number(record.id) === Number(formulaId)"
              color="processing"
            >
              当前
            </Tag>
          </template>
        </template>
      </Table>
      <Space class="gf-resolve-actions">
        <Button @click="step = 'choose'">返回</Button>
        <Button
          type="primary"
          :loading="submitting"
          :disabled="!validReplaceTargets.length || !selectedFormulaCount"
          @click="confirmReplace"
        >
          确认{{ validReplaceTargets.length > 1 ? '拆分' : '替换' }}（{{
            selectedFormulaCount
          }}
          个金方）
        </Button>
      </Space>
    </div>
  </Modal>
</template>
<style scoped>
.gf-resolve-tip {
  margin-bottom: 16px;
  color: hsl(var(--muted-foreground));
  line-height: 1.6;
}
.gf-resolve-search {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 12px;
}
.gf-resolve-search-label {
  flex-shrink: 0;
  color: hsl(var(--foreground));
  font-size: 13px;
}
.gf-resolve-search :deep(.chinese-drug-name-bubble),
.gf-resolve-search :deep(.chinese-drug-name-bubble--compact),
.gf-replace-search :deep(.chinese-drug-name-bubble),
.gf-replace-search :deep(.chinese-drug-name-bubble--compact) {
  width: 100% !important;
  min-width: 180px !important;
  max-width: none !important;
  flex: 1 1 auto !important;
}
.gf-resolve-selected {
  margin: 0 0 12px;
  color: hsl(var(--primary));
  font-size: 13px;
}
.gf-replace-targets {
  margin-bottom: 16px;
}
.gf-replace-row {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-bottom: 8px;
  padding: 8px 10px;
  border: 1px solid hsl(var(--border));
  border-radius: 8px;
  background: hsl(var(--card, var(--background)));
}
.gf-replace-row.is-active {
  border-color: hsl(var(--primary) / 0.55);
  background: hsl(var(--primary) / 0.06);
}
.gf-replace-idx {
  flex-shrink: 0;
  width: 20px;
  color: hsl(var(--muted-foreground));
  font-size: 12px;
  text-align: center;
}
.gf-replace-search {
  flex: 1 1 auto;
  min-width: 0;
}
.gf-replace-add {
  margin-top: 4px;
  margin-bottom: 8px;
}
.gf-split-preview {
  color: hsl(var(--primary));
  font-size: 12px;
  line-height: 1.5;
}
.gf-preview-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 8px;
}
.gf-preview-title {
  font-size: 13px;
  color: hsl(var(--foreground));
}
.gf-preview-table {
  margin-bottom: 16px;
}
.gf-resolve-actions {
  margin-top: 4px;
}
</style>
