// pdf-gen.jsx — generates the filled PDF by overlaying our values ON TOP of the
// real uploaded blank form. Uses the SAME buildDrawOps() / FIELD_COORDS as the
// on-screen preview, so what you see is what you get.
//
// The source page is rotated 270° (/Rotate). We bake that rotation into a fresh
// 792x612 landscape page, then draw text in plain landscape coords:
//   pdfX = op.x ,  pdfY = 612 - op.y   (op.y is the baseline from the top)

const SRC_PDF = 'uploads/' + encodeURIComponent('TIMESHEET NONUNION 2020-unlocked.pdf');
let _srcBytesCache = null;

async function _srcBytes() {
  if (_srcBytesCache) return _srcBytesCache;
  const resp = await fetch(SRC_PDF);
  _srcBytesCache = new Uint8Array(await resp.arrayBuffer());
  return _srcBytesCache;
}

function _dataUrlToBytes(dataUrl) {
  const b64 = dataUrl.split(',')[1];
  const bin = atob(b64);
  const arr = new Uint8Array(bin.length);
  for (let i = 0; i < bin.length; i++) arr[i] = bin.charCodeAt(i);
  return arr;
}

// Embeddable form fonts: jsDelivr Google-Fonts mirror TTFs (fetched + cached).
const FORM_FONT_URLS = {
  'Architects Daughter': 'https://cdn.jsdelivr.net/gh/google/fonts@main/ofl/architectsdaughter/ArchitectsDaughter-Regular.ttf',
  'Patrick Hand':        'https://cdn.jsdelivr.net/gh/google/fonts@main/ofl/patrickhand/PatrickHand-Regular.ttf',
  'Kalam':               'https://cdn.jsdelivr.net/gh/google/fonts@main/ofl/kalam/Kalam-Regular.ttf',
  'Permanent Marker':    'https://cdn.jsdelivr.net/gh/google/fonts@main/apache/permanentmarker/PermanentMarker-Regular.ttf',
  'Special Elite':       'https://cdn.jsdelivr.net/gh/google/fonts@main/apache/specialelite/SpecialElite-Regular.ttf',
  'Courier Prime':       'https://cdn.jsdelivr.net/gh/google/fonts@main/ofl/courierprime/CourierPrime-Regular.ttf',
  'Anton':               'https://cdn.jsdelivr.net/gh/google/fonts@main/ofl/anton/Anton-Regular.ttf',
  'Bebas Neue':          'https://cdn.jsdelivr.net/gh/google/fonts@main/ofl/bebasneue/BebasNeue-Regular.ttf',
  'Pacifico':            'https://cdn.jsdelivr.net/gh/google/fonts@main/ofl/pacifico/Pacifico-Regular.ttf',
  'Lobster':             'https://cdn.jsdelivr.net/gh/google/fonts@main/ofl/lobster/Lobster-Regular.ttf',
};
const _fontByteCache = {};
async function _fontBytes(url) {
  if (_fontByteCache[url]) return _fontByteCache[url];
  const r = await fetch(url);
  if (!r.ok) throw new Error('font fetch ' + r.status);
  const bytes = new Uint8Array(await r.arrayBuffer());
  _fontByteCache[url] = bytes;
  return bytes;
}

// Pick fonts (regular + bold) for the chosen Form font.
async function _formFonts(out, formFont) {
  const { StandardFonts } = window.PDFLib;
  const std = {
    Helvetica: [StandardFonts.Helvetica, StandardFonts.HelveticaBold],
    Times:     [StandardFonts.TimesRoman, StandardFonts.TimesRomanBold],
    Courier:   [StandardFonts.Courier, StandardFonts.CourierBold],
  };
  // custom embedded font (handwriting/display) — same face for regular & bold
  if (FORM_FONT_URLS[formFont] && window.fontkit) {
    try {
      out.registerFontkit(window.fontkit);
      const f = await out.embedFont(await _fontBytes(FORM_FONT_URLS[formFont]));
      return { font: f, fontB: f };
    } catch (e) { console.warn('form font embed failed, using Helvetica', e); }
  }
  const pair = std[formFont] || std.Helvetica;
  return { font: await out.embedFont(pair[0]), fontB: await out.embedFont(pair[1]) };
}

// Stamp the signature cleanly: knock any white/light background out to transparency
// at EXPORT time, so even an older signature saved with a solid white box prints as
// just the ink. Always returns a transparent PNG data URL (falls back to the original
// on any error). knockoutBackground / trimToTransparentPNG come from tc-sign.jsx.
function _cleanSignatureDataUrl(dataUrl) {
  return new Promise((resolve) => {
    try {
      const img = new Image();
      img.onload = () => {
        try {
          const c = document.createElement('canvas');
          c.width = img.naturalWidth; c.height = img.naturalHeight;
          c.getContext('2d').drawImage(img, 0, 0);
          if (window.knockoutBackground) window.knockoutBackground(c);
          const out = (window.trimToTransparentPNG && window.trimToTransparentPNG(c, 4)) || c.toDataURL('image/png');
          resolve(out || dataUrl);
        } catch (e) { resolve(dataUrl); }
      };
      img.onerror = () => resolve(dataUrl);
      img.src = dataUrl;
    } catch (e) { resolve(dataUrl); }
  });
}

async function buildTimecardPDFBytes(data) {
  const { PDFDocument, StandardFonts, rgb, degrees } = window.PDFLib;
  const W = FORM.w, H = FORM.h;                 // 792 x 612

  const srcDoc = await PDFDocument.load(await _srcBytes());
  const out = await PDFDocument.create();
  const [srcPage] = srcDoc.getPages();
  const embedded = await out.embedPage(srcPage); // intrinsic 612 x 792 (pre-rotation)

  const page = out.addPage([W, H]);
  // bake the 270° page rotation: draw embedded content rotated 90° CCW into place
  page.drawPage(embedded, { x: W, y: 0, rotate: degrees(90) });

  const { font } = await _formFonts(out, data.formFont);
  const ink = (() => { const m = FILL_COLOR.replace('#', '');
    return rgb(parseInt(m.slice(0,2),16)/255, parseInt(m.slice(2,4),16)/255, parseInt(m.slice(4,6),16)/255); })();

  const ops = buildDrawOps(data);
  for (const op of ops) {
    let size = op.size;
    if (op.maxW) {
      while (size > 5 && font.widthOfTextAtSize(op.text, size) > op.maxW) size -= 0.5;
    }
    const w = font.widthOfTextAtSize(op.text, size);
    let x = op.x;
    if (op.align === 'center') x = op.x - w / 2;
    // mask the form's grid lines behind spanning labels (e.g. DOWN) so letters read cleanly
    if (op.bg) {
      const padX = 3, top = H - op.y + size * 0.80, h = size * 1.05;
      page.drawRectangle({ x: x - padX, y: top - h, width: w + padX * 2, height: h, color: rgb(1, 1, 1) });
    }
    page.drawText(op.text, { x, y: H - op.y, size, font, color: ink });
  }

  // signature image
  if (data.profile.signature) {
    try {
      const c = FIELD_COORDS.signature;
      const clean = await _cleanSignatureDataUrl(data.profile.signature);
      const img = await out.embedPng(_dataUrlToBytes(clean));
      let dw = img.width, dh = img.height;
      const scale = Math.min(c.maxW / dw, c.maxH / dh);
      dw *= scale; dh *= scale;
      page.drawImage(img, { x: c.x, y: H - c.y, width: dw, height: dh });
    } catch (e) { console.warn('signature embed failed', e); }
  }

  _drawAnnotations(page, data.card && data.card.annotations, font, ink, H);

  return await out.save();
}

// Draw free-text annotations onto the page. Coords are FORM units (y = box top).
// Multi-line via \n. Falls back to ASCII if the chosen font can't encode a glyph.
function _drawAnnotations(page, anns, font, ink, H) {
  if (!Array.isArray(anns)) return;
  for (const a of anns) {
    const raw = (a && a.text ? String(a.text) : '').replace(/\r/g, '');
    if (!raw.trim()) continue;
    const size = a.size || 11;
    const step = size * 1.15;
    const firstBase = (a.y || 0) + size * 0.86;
    const lines = raw.split('\n');
    lines.forEach((ln, i) => {
      if (!ln) return;
      const y = H - (firstBase + i * step);
      try {
        page.drawText(ln, { x: a.x || 0, y, size, font, color: ink });
      } catch (e) {
        try { page.drawText(ln.replace(/[^\x20-\x7E]/g, ''), { x: a.x || 0, y, size, font, color: ink }); }
        catch (e2) { /* skip unrenderable line */ }
      }
    });
  }
}

function downloadBytes(bytes, filename) {
  const blob = new Blob([bytes], { type: 'application/pdf' });
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url; a.download = filename;
  document.body.appendChild(a); a.click();
  setTimeout(() => { URL.revokeObjectURL(url); a.remove(); }, 1500);
}

// ── Kit / Box Rental form (portrait, no rotation) ────────────────────────────
const KIT_SRC_PDF = 'uploads/' + encodeURIComponent('KIT RENTAL FORM.pdf');
let _kitSrcCache = null;
async function _kitSrcBytes() {
  if (_kitSrcCache) return _kitSrcCache;
  const resp = await fetch(KIT_SRC_PDF);
  _kitSrcCache = new Uint8Array(await resp.arrayBuffer());
  return _kitSrcCache;
}

async function buildKitPDFBytes(data) {
  const { PDFDocument, StandardFonts, rgb } = window.PDFLib;
  const W = KIT_FORM.w, H = KIT_FORM.h;            // 612 x 792, no rotation
  const srcDoc = await PDFDocument.load(await _kitSrcBytes());
  const out = await PDFDocument.create();
  const [srcPage] = srcDoc.getPages();
  const embedded = await out.embedPage(srcPage);
  const page = out.addPage([W, H]);
  page.drawPage(embedded, { x: 0, y: 0 });

  // paint white over the pre-printed signature baked into the blank form
  for (const r of KIT_WHITEOUT) {
    page.drawRectangle({ x: r.x, y: H - (r.y + r.h), width: r.w, height: r.h, color: rgb(1, 1, 1) });
  }

  const { font, fontB } = await _formFonts(out, data.formFont);
  const ink = (() => { const m = KIT_FILL.replace('#', '');
    return rgb(parseInt(m.slice(0,2),16)/255, parseInt(m.slice(2,4),16)/255, parseInt(m.slice(4,6),16)/255); })();

  const ops = buildKitDrawOps(data);
  for (const op of ops) {
    if (op.isCheck) {
      // center the 'X' glyph on the box center (cx, cy)
      const size = op.size;
      const w = fontB.widthOfTextAtSize(op.text, size);
      const capH = fontB.heightAtSize(size, { descender: false });
      const x = op.cx - w / 2;
      const baseline = op.cy + capH / 2;          // glyph visual center at cy
      page.drawText(op.text, { x, y: H - baseline, size, font: fontB, color: ink });
      continue;
    }
    let size = op.size;
    if (op.maxW) { while (size > 5 && font.widthOfTextAtSize(op.text, size) > op.maxW) size -= 0.5; }
    const w = font.widthOfTextAtSize(op.text, size);
    let x = op.x;
    if (op.align === 'center') x = op.x - w / 2;
    page.drawText(op.text, { x, y: H - op.y, size, font, color: ink });
  }

  if (data.profile.signature) {
    try {
      const c = KIT_COORDS.signature;
      const clean = await _cleanSignatureDataUrl(data.profile.signature);
      const img = await out.embedPng(_dataUrlToBytes(clean));
      let dw = img.width, dh = img.height;
      const scale = Math.min(c.maxW / dw, c.maxH / dh);
      dw *= scale; dh *= scale;
      page.drawImage(img, { x: c.x, y: H - c.y, width: dw, height: dh });
    } catch (e) { console.warn('kit signature embed failed', e); }
  }

  _drawAnnotations(page, data.kit && data.kit.annotations, font, ink, H);

  return await out.save();
}

async function generateKitPDF(data) {
  const bytes = await buildKitPDFBytes(data);
  const pattern = data.profile && data.profile.fileNamePatternKit;
  const fname = kitFilename(data.kit.weekEnding, data.initials, data.kit.kitType, pattern);
  downloadBytes(bytes, fname);
  return fname;
}

Object.assign(window, { buildTimecardPDFBytes, generateTimecardPDF, downloadBytes, buildKitPDFBytes, generateKitPDF });

async function generateTimecardPDF(data) {
  const bytes = await buildTimecardPDFBytes(data);
  const pattern = data.profile && data.profile.fileNamePatternTC;
  const project = data.card && data.card.projectTitle;
  const fname = pdfFilename(data.parsed.weekEnding, data.initials, pattern, project);
  downloadBytes(bytes, fname);
  return fname;
}

Object.assign(window, { buildTimecardPDFBytes, generateTimecardPDF, downloadBytes });
