import { unlink, writeFile } from 'node:fs/promises';
import { join } from 'node:path';

import { app, BrowserWindow } from 'electron';
import log from 'electron-log/main';

/**
 * 静默打印：隐藏窗口加载 HTML → webContents.print 直接出纸
 * 为什么用隐藏窗口：渲染层的处方打印本来就是拼好的完整 HTML（含内联样式），
 * 加载到独立隐藏窗口打印可以完全复用现有模板，且不阻塞/不干扰主窗口。
 * 为什么落临时文件而不是 data: URL：处方 HTML 可能较大，data URL 有长度上限风险，
 * 临时文件 loadFile 对任意大小都稳定，打完即删。
 */

export interface PrintHtmlOptions {
  /** 完整的打印 HTML（含样式），由渲染层拼好传入 */
  html: string;
  /** 目标打印机名称；不传时使用系统默认打印机 */
  deviceName?: string;
  /** 是否静默打印（true 不弹系统打印对话框） */
  silent?: boolean;
}

export interface PrintResult {
  ok: boolean;
  message?: string;
}

/**
 * 执行打印，返回是否成功与失败原因（渲染层据此提示用户）
 */
export async function printHtml(options: PrintHtmlOptions): Promise<PrintResult> {
  const { html, deviceName, silent = true } = options;
  // 临时文件带时间戳防并发打印互相覆盖
  const tempFile = join(app.getPath('temp'), `xk-print-${Date.now()}-${Math.random().toString(36).slice(2)}.html`);
  await writeFile(tempFile, html, 'utf8');

  return new Promise<PrintResult>((resolve) => {
    let settled = false;
    const win = new BrowserWindow({
      show: false,
      webPreferences: { sandbox: true },
    });

    /** 统一收尾：销毁隐藏窗口、清理临时文件、只 resolve 一次 */
    const finish = (ok: boolean, message?: string) => {
      if (settled) return;
      settled = true;
      if (!win.isDestroyed()) win.destroy();
      unlink(tempFile).catch(() => {});
      if (!ok) log.warn(`静默打印失败: ${message}`);
      resolve({ ok, message });
    };

    win.webContents.once('did-finish-load', () => {
      win.webContents.print(
        {
          silent,
          deviceName: deviceName || undefined,
          printBackground: true,
        },
        (success, failureReason) => finish(success, success ? undefined : failureReason),
      );
    });

    win.webContents.once('did-fail-load', (_event, _code, desc) => finish(false, desc));

    // 兜底超时：防止打印机脱机等场景下隐藏窗口泄漏
    setTimeout(() => finish(false, '打印超时（请检查打印机状态）'), 60_000);

    win.loadFile(tempFile).catch((error: unknown) => {
      finish(false, error instanceof Error ? error.message : String(error));
    });
  });
}
