<template>
  <a-modal
    v-model:open="innerOpen"
    :title="modalTitle"
    width="960px"
    :footer="null"
    destroy-on-close
    wrap-class-name="raw-material-card-print-preview-modal"
    @cancel="onClose"
  >
    <a-spin :spinning="loading">
      <div v-if="errorText" class="preview-error">{{ errorText }}</div>
      <div v-else class="preview-body">
        <iframe
          v-if="previewHtml"
          ref="previewIframeRef"
          class="preview-iframe"
          title="原材料卡片打印预览"
          :srcdoc="previewHtml"
        />
        <a-empty v-else-if="!loading" description="暂无预览内容" />
      </div>
    </a-spin>
    <div class="preview-footer">
      <a-space>
        <a-button @click="innerOpen = false">关闭</a-button>
        <a-button type="primary" :disabled="!previewHtml || !!errorText" @click="handleBrowserPrint">
          <Icon icon="ant-design:printer-outlined" />
          浏览器打印
        </a-button>
      </a-space>
    </div>
  </a-modal>
</template>

<script lang="ts" setup>
  import { computed, ref, watch } from 'vue';
  import { Icon } from '/@/components/Icon';
  import { useMessage } from '/@/hooks/web/useMessage';
  import { prepareNativePrint } from '../MesXslRawMaterialCard.api';
  import { renderNativePrintHtml } from '/@/views/print/template/native/core/printRenderer';
  import { normalizeImportedNativeSchema } from '/@/views/print/template/native/core/nativeSchemaNormalize';

  const props = defineProps<{
    open: boolean;
    /** 卡片主键，有值时拉取模板与业务数据并渲染 */
    cardId: string | null;
    /** 展示在标题上的条码/说明 */
    barcode?: string;
  }>();

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

  const { createMessage } = useMessage();

  const innerOpen = computed({
    get: () => props.open,
    set: (v: boolean) => emit('update:open', v),
  });

  const modalTitle = computed(() => {
    const b = String(props.barcode || '').trim();
    return b ? `原材料卡片打印预览（条码：${b}）` : '原材料卡片打印预览';
  });

  const loading = ref(false);
  const errorText = ref('');
  const previewHtml = ref('');
  const previewIframeRef = ref<HTMLIFrameElement | null>(null);

  async function loadPreview(id: string) {
    loading.value = true;
    errorText.value = '';
    previewHtml.value = '';
    try {
      const prep = (await prepareNativePrint(id)) as Record<string, unknown>;
      const templateJsonRaw = prep.templateJson as string;
      const printData = prep.printData as Record<string, unknown>;
      if (!templateJsonRaw) {
        throw new Error('模板 JSON 为空，请检查「业务打印绑定」是否已配置');
      }
      let raw: unknown;
      try {
        raw = typeof templateJsonRaw === 'string' ? JSON.parse(templateJsonRaw) : templateJsonRaw;
      } catch {
        throw new Error('模板 JSON 格式错误');
      }
      const schema = normalizeImportedNativeSchema(raw);
      previewHtml.value = await renderNativePrintHtml(schema, printData as Record<string, unknown>);
    } catch (e: unknown) {
      errorText.value = e instanceof Error ? e.message : String(e);
    } finally {
      loading.value = false;
    }
  }

  /**
   * 在 Modal 内对 iframe 直接 print() 时，打印对话框易被遮罩层级挡住或焦点异常，表现为「点了没反应」。
   * 改为在 body 下挂临时 iframe、写入同一套 HTML 再打印，与模板预览常用做法一致。
   */
  function handleBrowserPrint() {
    const html = previewHtml.value;
    if (!html?.trim()) {
      createMessage.warning('预览未就绪，请稍后再试');
      return;
    }
    const iframe = document.createElement('iframe');
    iframe.setAttribute(
      'style',
      'position:fixed;left:0;top:0;width:0;height:0;border:0;opacity:0;pointer-events:none;',
    );
    document.body.appendChild(iframe);
    const doc = iframe.contentDocument;
    if (!doc) {
      document.body.removeChild(iframe);
      createMessage.error('无法创建打印文档');
      return;
    }
    try {
      doc.open();
      doc.write(html);
      doc.close();
    } catch {
      document.body.removeChild(iframe);
      createMessage.error('写入打印内容失败');
      return;
    }

    const cleanup = () => {
      try {
        if (iframe.parentNode) {
          document.body.removeChild(iframe);
        }
      } catch {
        // ignore
      }
    };

    const runPrint = () => {
      try {
        const w = iframe.contentWindow;
        if (!w) {
          createMessage.error('无法唤起打印窗口');
          cleanup();
          return;
        }
        w.focus();
        w.print();
        /** 关闭打印对话框后移除临时 iframe（部分浏览器支持 afterprint） */
        w.addEventListener('afterprint', cleanup, { once: true });
        window.setTimeout(cleanup, 120000);
      } catch {
        createMessage.error('无法唤起打印，请检查浏览器弹窗/打印权限');
        cleanup();
      }
    };

    /** 等待排版与字体后再打印，减少空白页 */
    window.setTimeout(runPrint, 100);
  }

  function onClose() {
    errorText.value = '';
    previewHtml.value = '';
  }

  watch(
    () => [props.open, props.cardId] as const,
    ([isOpen, id]) => {
      if (isOpen && id) {
        void loadPreview(id);
      }
      if (!isOpen) {
        onClose();
      }
    },
  );
</script>

<style lang="less" scoped>
  .preview-error {
    color: #cf1322;
    padding: 8px 0;
  }

  .preview-body {
    min-height: 420px;
    max-height: 72vh;
    overflow: auto;
    border: 1px solid #f0f0f0;
    border-radius: 4px;
    background: #fafafa;
  }

  .preview-iframe {
    display: block;
    width: 100%;
    min-height: 400px;
    border: 0;
    background: #fff;
  }

  .preview-footer {
    margin-top: 16px;
    padding-top: 12px;
    border-top: 1px solid #f0f0f0;
    text-align: right;
  }
</style>
