export interface PrintExportPayload {
  fileName: string;
  title: string;
  html: string;
  previewFont: string;
  previewFontSize: number;
  previewFontFaceCss?: string;
}

export const PRINT_EXPORT_QUERY_PARAM = 'printJob';

const PRINT_DOCUMENT_CSP = [
  "default-src 'none'",
  "style-src 'unsafe-inline'",
  "img-src data: blob: https: http:",
  "font-src data:",
  "object-src 'none'",
  "base-uri 'none'",
].join('; ');

export const getNoteTitleFromContent = (content: string) => {
  const firstLine = content
    .split('\n')
    .map((line) => line.trim())
    .find((line) => line.length > 0);

  return (firstLine || 'Untitled').replace(/^#+\s*/, '').trim();
};

export const sanitizeFileName = (name: string) =>
  name
    .replace(/[\\/:*?"<>|]/g, '-')
    .replace(/\s+/g, ' ')
    .trim() || 'note';

const escapeHtml = (value: string) =>
  value
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&#39;');

const escapeFontFamily = (value: string) =>
  value.replace(/["\\]/g, '\\$&');

interface PrintFontAsset {
  fileName: string;
  fontStyle: 'normal' | 'italic';
  fontWeight: string;
}

const PRINT_FONT_ASSETS: Record<string, PrintFontAsset[]> = {
  Merriweather: [
    {
      fileName: 'Merriweather-VariableFont_opsz,wdth,wght.ttf',
      fontStyle: 'normal',
      fontWeight: '300 900',
    },
    {
      fileName: 'Merriweather-Italic-VariableFont_opsz,wdth,wght.ttf',
      fontStyle: 'italic',
      fontWeight: '300 900',
    },
  ],
  'Crimson Pro': [
    {
      fileName: 'CrimsonPro-VariableFont_wght.ttf',
      fontStyle: 'normal',
      fontWeight: '200 900',
    },
    {
      fileName: 'CrimsonPro-Italic-VariableFont_wght.ttf',
      fontStyle: 'italic',
      fontWeight: '200 900',
    },
  ],
  'Roboto Serif': [
    {
      fileName: 'RobotoSerif-VariableFont_GRAD,opsz,wdth,wght.ttf',
      fontStyle: 'normal',
      fontWeight: '100 900',
    },
    {
      fileName: 'RobotoSerif-Italic-VariableFont_GRAD,opsz,wdth,wght.ttf',
      fontStyle: 'italic',
      fontWeight: '100 900',
    },
  ],
  Average: [
    {
      fileName: 'Average-Regular.ttf',
      fontStyle: 'normal',
      fontWeight: '400',
    },
  ],
};

const fontDataUrlCache = new Map<string, Promise<string>>();

const blobToDataUrl = (blob: Blob) =>
  new Promise<string>((resolve, reject) => {
    const reader = new FileReader();
    reader.onloadend = () => resolve(reader.result as string);
    reader.onerror = () => reject(reader.error ?? new Error('Failed to read font file.'));
    reader.readAsDataURL(blob);
  });

const getBundledFontUrl = (fileName: string) =>
  new URL(`./fonts/${fileName}`, window.location.href).toString();

const loadBundledFontDataUrl = async (fileName: string) => {
  const cached = fontDataUrlCache.get(fileName);
  if (cached) {
    return cached;
  }

  const pending = (async () => {
    const response = await fetch(getBundledFontUrl(fileName));
    if (!response.ok) {
      throw new Error(`Failed to load bundled font ${fileName}: ${response.status}`);
    }

    return blobToDataUrl(await response.blob());
  })();

  fontDataUrlCache.set(fileName, pending);
  return pending;
};

export const loadPrintFontFaceCss = async (fontFamily: string) => {
  const fontAssets = PRINT_FONT_ASSETS[fontFamily];
  if (!fontAssets) {
    return '';
  }

  const rules = await Promise.all(
    fontAssets.map(async ({ fileName, fontStyle, fontWeight }) => {
      try {
        const dataUrl = await loadBundledFontDataUrl(fileName);
        return `@font-face {
  font-family: "${escapeFontFamily(fontFamily)}";
  font-style: ${fontStyle};
  font-weight: ${fontWeight};
  font-display: swap;
  src: url("${dataUrl}") format("truetype");
}`;
      } catch (error) {
        console.error(`Failed to embed preview font "${fontFamily}" from ${fileName}:`, error);
        return '';
      }
    })
  );

  return rules.filter(Boolean).join('\n');
};

export const buildPrintDocument = (payload: PrintExportPayload) => {
  const fontFamily = `"${escapeFontFamily(payload.previewFont)}", Georgia, serif`;

  return `<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta http-equiv="Content-Security-Policy" content="${PRINT_DOCUMENT_CSP}" />
    <title>${escapeHtml(payload.fileName)}</title>
    <style>
      ${payload.previewFontFaceCss ?? ''}

      :root {
        color-scheme: light;
      }

      * {
        box-sizing: border-box;
      }

      html,
      body {
        margin: 0;
        padding: 0;
        background: #ffffff;
        color: #0f172a;
      }

      body {
        font-family: ${fontFamily};
        font-size: ${payload.previewFontSize}px;
        line-height: 1.7;
        -webkit-print-color-adjust: exact;
        print-color-adjust: exact;
      }

      @page {
        size: A4;
        margin: 18mm 16mm 18mm 16mm;
      }

      article {
        color: #0f172a;
      }

      .print-note h1,
      .print-note h2,
      .print-note h3 {
        color: #020617;
        font-weight: 700;
        page-break-after: avoid;
      }

      .print-note h1 {
        font-size: 2em;
        line-height: 1.15;
        margin: 0 0 1.35em;
        letter-spacing: -0.015em;
        text-align: center;
      }

      .print-note h2 {
        font-size: 1.55em;
        line-height: 1.2;
        margin: 1.25em 0 0.45em;
      }

      .print-note h3 {
        font-size: 1.25em;
        line-height: 1.3;
        margin: 1.1em 0 0.4em;
      }

      .print-note p {
        margin: 0 0 0.9em;
      }

      .print-note ul,
      .print-note ol {
        margin: 0.75em 0 1em;
        padding-left: 1.7em;
        list-style-position: outside;
      }

      .print-note ul {
        list-style-type: disc;
      }

      .print-note ol {
        list-style-type: decimal;
      }

      .print-note li {
        margin: 0.28em 0;
        padding-left: 0.18em;
      }

      .print-note li > p {
        margin: 0;
      }

      .print-note li::marker {
        color: #334155;
      }

      .print-note blockquote {
        margin: 1.15em 0;
        padding-left: 1em;
        border-left: 3px solid #cbd5e1;
        color: #475569;
        font-style: italic;
      }

      .print-note blockquote > :first-child {
        margin-top: 0;
      }

      .print-note blockquote > :last-child {
        margin-bottom: 0;
      }

      .print-note pre {
        margin: 1.15em 0 1.3em;
        padding: 0.95em 1.05em;
        overflow-x: auto;
        border: 1px solid #dbe4f0;
        border-radius: 12px;
        background: #f5f7fb;
        color: #0f172a;
        page-break-inside: avoid;
      }

      .print-note pre code {
        background: transparent;
        border: 0;
        padding: 0;
        border-radius: 0;
        font-size: 0.92em;
        color: inherit;
      }

      .print-note code {
        font-family: "SFMono-Regular", "SF Mono", "JetBrains Mono", "Fira Code", "Source Code Pro", Menlo, Consolas, monospace;
        font-size: 0.92em;
        padding: 0.08em 0.38em;
        border: 1px solid #dbe4f0;
        border-radius: 0.42em;
        background: #f5f7fb;
        color: #0f172a;
      }

      .print-note a {
        color: #2563eb;
        text-decoration: underline;
        text-decoration-thickness: 0.08em;
        text-underline-offset: 0.14em;
      }

      .print-note strong {
        font-weight: 700;
      }

      .print-note em {
        font-style: italic;
      }

      .print-note del {
        text-decoration: line-through;
      }

      .print-note hr {
        border: 0;
        border-top: 1px solid #cbd5e1;
        margin: 1.6em 0;
      }

      .print-note img {
        display: block;
        max-width: 100%;
        height: auto;
        margin: 1.2em auto;
        border-radius: 12px;
        page-break-inside: avoid;
      }

      .print-note table {
        width: 100%;
        border-collapse: collapse;
        margin: 1em 0 1.2em;
        font-size: 0.95em;
      }

      .print-note th,
      .print-note td {
        border: 1px solid #dbe4f0;
        padding: 0.5em 0.65em;
        text-align: left;
        vertical-align: top;
      }

      .print-note th {
        background: #f8fafc;
        font-weight: 600;
      }
    </style>
  </head>
  <body>
    <article class="print-note">${payload.html}</article>
  </body>
</html>`;
};
