import {
  buildPrintDocument,
  PrintExportPayload,
  PRINT_EXPORT_QUERY_PARAM,
} from '../printExport';

export interface DesktopMessageOptions {
  title?: string;
  kind?: 'info' | 'warning' | 'error';
}

interface ExportPdfResult {
  canceled: boolean;
  filePath?: string;
}

const isElectronRuntime = () =>
  typeof window !== 'undefined' && typeof window.electronDesktop !== 'undefined';

const isTauriRuntime = () =>
  typeof window !== 'undefined' &&
  (
    typeof (window as Window & { __TAURI__?: unknown }).__TAURI__ !== 'undefined' ||
    typeof (window as Window & { __TAURI_INTERNALS__?: unknown }).__TAURI_INTERNALS__ !== 'undefined'
  );

export const getDesktopRuntime = () => {
  if (isElectronRuntime()) return 'electron';
  if (isTauriRuntime()) return 'tauri';
  return 'browser';
};

export const showDesktopMessage = async (
  messageText: string,
  options: DesktopMessageOptions = {}
) => {
  if (window.electronDesktop) {
    await window.electronDesktop.showMessage({
      message: messageText,
      ...options,
    });
    return;
  }

  if (isTauriRuntime()) {
    const { message } = await import('@tauri-apps/plugin-dialog');
    await message(messageText, options);
    return;
  }

  window.alert(messageText);
};

export const exportPdfDocument = async (
  payload: PrintExportPayload
): Promise<ExportPdfResult> => {
  if (window.electronDesktop) {
    return window.electronDesktop.exportPdf({
      ...payload,
      documentHtml: buildPrintDocument(payload),
    });
  }

  if (isTauriRuntime()) {
    await exportPdfDocumentWithTauri(payload);
    return { canceled: false };
  }

  throw new Error('PDF export is only available in a desktop runtime.');
};

async function exportPdfDocumentWithTauri(payload: PrintExportPayload) {
  const [{ emitTo, listen }, { WebviewWindow }] = await Promise.all([
    import('@tauri-apps/api/event'),
    import('@tauri-apps/api/webviewWindow'),
  ]);

  const jobId = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
  const windowLabel = `print-export-${jobId}`;
  let printWindow: any = null;
  let unlistenReady: any = null;

  try {
    await new Promise<void>((resolve, reject) => {
      let settled = false;
      const timeoutId = window.setTimeout(() => {
        if (settled) return;
        settled = true;
        unlistenReady?.();
        reject(new Error('Print view initialization timed out.'));
      }, 10000);

      listen<{ jobId: string }>('print-export-ready', (event) => {
        if (settled || event.payload.jobId !== jobId) return;

        settled = true;
        window.clearTimeout(timeoutId);
        unlistenReady?.();

        void emitTo(windowLabel, 'print-export-payload', payload)
          .then(() => resolve())
          .catch(reject);
      })
        .then((unlisten) => {
          unlistenReady = unlisten;
          printWindow = new WebviewWindow(windowLabel, {
            url: `/?${PRINT_EXPORT_QUERY_PARAM}=${encodeURIComponent(jobId)}`,
            title: 'Opening Print Dialog',
            width: 960,
            height: 1100,
            center: true,
            visible: true,
            focus: true,
            skipTaskbar: true,
            resizable: false,
            parent: 'main',
          });

          void printWindow.once('tauri://error', (event: { payload?: unknown }) => {
            if (settled) return;
            settled = true;
            window.clearTimeout(timeoutId);
            unlistenReady?.();
            reject(new Error(String(event.payload ?? 'Failed to create print window.')));
          });
        })
        .catch(reject);
    });
  } catch (error) {
    if (printWindow) {
      void printWindow.close().catch(() => undefined);
    }
    throw error;
  } finally {
    if (typeof unlistenReady === 'function') {
      unlistenReady();
    }
  }
}
