/* ============================================================
   overlay.jsx — 배너 오버레이(선택항목) 공용 렌더러 · window.BannerOverlay
   ------------------------------------------------------------
   목적(B안): "선택항목(로고·부가정보)"을 배치(rects)와 분리된 오버레이 레이어로 보고,
   저장(캔버스)에서도 화면과 "똑같이" 합성한다. 배치 로직/규칙은 절대 건드리지 않는다.
   좌표계 = 550×550 (화면 apOverlayEls/DecoBadge/AddTextBadge 와 동일 위치·스타일).
   · drawStandard(ctx, {logos, deco}, opts) : A/B/C/D 공통 — 로고(우상단) + deco(기본 위치)
   · drawDeco(ctx, deco, x, y, opts)        : deco 뱃지 1개를 (x,y)에 (E 보험 등 커스텀 위치용)
   deco.kind: 'text' | 'image' | 'flag' | 'mark' | 'color'  (화면 DecoBadge 와 동일)
   ============================================================ */
(function () {
  const NL = String.fromCharCode(10);
  const PURPLE = 'rgba(104,10,186,0.9)';
  const PURPLE_FLAG = 'rgba(104,10,186,0.92)';

  function loadImg(url) {
    return new Promise((res, rej) => { const im = new Image(); im.crossOrigin = 'anonymous'; im.onload = () => res(im); im.onerror = rej; im.src = url; });
  }
  function setHighQualityImageSmoothing(ctx) {
    if (!ctx) return;
    ctx.imageSmoothingEnabled = true;
    try { ctx.imageSmoothingQuality = 'high'; } catch (e) {}
  }
  function rrect(ctx, x, y, w, h, r) {
    r = Math.min(r, w / 2, h / 2);
    ctx.beginPath();
    ctx.moveTo(x + r, y);
    ctx.arcTo(x + w, y, x + w, y + h, r);
    ctx.arcTo(x + w, y + h, x, y + h, r);
    ctx.arcTo(x, y + h, x, y, r);
    ctx.arcTo(x, y, x + w, y, r);
    ctx.closePath();
  }

  // ── 부가텍스트 뱃지(원형 + parseBadge 레이아웃) — AddTextBadge(size=90) 이식 ──
  function parseBadge(raw) {
    const s = String(raw || '').split(String.fromCharCode(13)).join('').trim();
    if (!s) return { kind: 'empty' };
    if (s.indexOf(NL) >= 0) { const lines = s.split(NL).map((x) => x.trim()).filter(Boolean).slice(0, 3); return { kind: 'lines', lines }; }
    let m = s.match(/^[x×X][ ]*([0-9]{1,4})$/); if (m) return { kind: 'times', num: m[1] };
    m = s.match(/^([0-9]{1,4})[ ]*([가-힣]{1,3})$/); if (m) return { kind: 'numUnit', num: m[1], unit: m[2] };
    m = s.match(/^([0-9]{1,4})[ ]*[xX×][ ]*([0-9]{1,4})$/); if (m) return { kind: 'dim', a: m[1], b: m[2] };
    if (s.indexOf(' ') >= 0) { const parts = s.split(/[ ]+/).filter(Boolean); const lines = parts.length > 3 ? [parts[0], parts[1], parts.slice(2).join(' ')] : parts; return { kind: 'lines', lines }; }
    const plus = s.indexOf('+');
    if (plus > 0 && plus < s.length - 1 && s.length > 4) return { kind: 'lines', lines: [s.slice(0, plus + 1), s.slice(plus + 1)] };
    if (/[가-힣]/.test(s) && s.length > 4) { const n = s.length > 8 ? 3 : 2; const per = Math.ceil(s.length / n); const arr = []; for (let i = 0; i < s.length; i += per) arr.push(s.slice(i, i + per)); return { kind: 'lines', lines: arr.slice(0, 3) }; }
    return { kind: 'single', text: s };
  }
  const KRFONT = '"Noto Sans KR", "Noto Sans CJK KR", Pretendard, sans-serif';
  function logoAspect(value) {
    const n = Number(value);
    return Number.isFinite(n) && n > 0 ? Math.max(0.25, Math.min(20, n)) : 1;
  }
  function decoZoom(value) {
    const n = Number(value);
    return Number.isFinite(n) && n > 0 ? Math.max(0.5, Math.min(3, n)) : 1;
  }
  function logoOrient(g) {
    if (g && (g.orient === 'h' || g.orient === 'v')) return g.orient;
    return logoAspect(g && g.aspect) >= 1.6 ? 'h' : 'v';
  }
  function logoScale(g) {
    const n = Number(g && g.scale);
    return Number.isFinite(n) && n > 0 ? Math.max(0.25, Math.min(4, n)) : 1;
  }
  function logoScaleW(g) {
    const n = Number(g && g.scaleW);
    if (Number.isFinite(n) && n > 0) return Math.max(0.25, Math.min(4, n));
    return logoScale(g);
  }
  function logoScaleH(g) {
    const n = Number(g && g.scaleH);
    if (Number.isFinite(n) && n > 0) return Math.max(0.25, Math.min(4, n));
    return logoScale(g);
  }
  function drawTextBadge(ctx, text, cx, cy, size) {
    const k = (size || 90) / 90;
    cy -= 2 * k;
    const p = parseBadge(text);
    const INNER = 73.8;
    const fitW = (len, cap) => Math.min(cap, INNER / (Math.max(1, len) * 0.6));
    const fitH = (n, cap) => Math.min(cap, 75 / (n * 1.18));
    ctx.save();
    ctx.fillStyle = '#fff';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    const F = (fs, w) => (w || 500) + ' ' + (fs * k) + 'px ' + KRFONT;
    if (p.kind === 'empty') { ctx.restore(); return; }
    if (p.kind === 'times') {
      const nf = Math.min(40, fitW(String(p.num).length + 1.1, 40));
      ctx.font = F(nf, 400); const xw = ctx.measureText('×').width;
      ctx.font = F(nf, 500); const nw = ctx.measureText(p.num).width;
      const tot = xw + nw; let x = cx - tot / 2;
      ctx.textAlign = 'left'; ctx.font = F(nf * 0.75, 400); ctx.fillText('×', x, cy); x += xw;
      ctx.font = F(nf, 500); ctx.fillText(p.num, x, cy);
      ctx.restore(); return;
    }
    if (p.kind === 'numUnit') {
      const nf = Math.min(36, (INNER - p.unit.length * 20 * 0.55) / (String(p.num).length * 0.55));
      ctx.textAlign = 'left';
      ctx.font = F(nf, 500); const nw = ctx.measureText(p.num).width;
      ctx.font = F(20, 400); const uw = ctx.measureText(p.unit).width;
      let x = cx - (nw + uw + 1 * k) / 2;
      ctx.font = F(nf, 500); ctx.fillText(p.num, x, cy); x += nw + 1 * k;
      ctx.font = F(20, 400); ctx.fillText(p.unit, x, cy);
      ctx.restore(); return;
    }
    if (p.kind === 'dim') {
      const fs = Math.min(20, INNER / ((p.a.length + p.b.length) * 0.55 + 0.6));
      ctx.font = F(fs, 500); const s = p.a + 'x' + p.b;
      ctx.textAlign = 'center'; ctx.fillText(s, cx, cy);
      ctx.restore(); return;
    }
    if (p.kind === 'single') { const fs = fitW(p.text.length, 36); ctx.font = F(fs, 500); ctx.fillText(p.text, cx, cy); ctx.restore(); return; }
    // lines
    const lines = p.lines; const maxLen = Math.max.apply(null, lines.map((l) => l.length).concat(1));
    const brand = lines.length < 3 && maxLen <= 2;
    const base = lines.length >= 3 ? 18.5 : brand ? 36 : 20;
    const fs = Math.min(base, fitW(maxLen, base), fitH(lines.length, base));
    const llh = (lines.length >= 3 ? 1.24 : 1.2) * fs * k;
    ctx.font = F(fs, brand ? 500 : 400);
    const total = llh * lines.length; let y = cy - total / 2 + llh / 2;
    lines.forEach((l) => { ctx.fillText(l, cx, y); y += llh; });
    ctx.restore();
  }

  function flagTextLines(raw) {
    const def = '인증' + NL + '플래그';
    const lines = String(raw || def).split(String.fromCharCode(13)).join('').split(NL).map((x) => x.trim()).filter(Boolean).slice(0, 2);
    return lines.length ? lines : def.split(NL);
  }

  function normalizeFlagItems(items, count) {
    const src = Array.isArray(items) ? items : [];
    const out = [];
    for (let i = 0; i < (count || 1); i++) {
      const item = src[i] || {};
      out.push({ mode: item.mode === 'image' ? 'image' : 'text', text: item.text != null ? String(item.text) : '인증' + NL + '플래그', src: item.src || null });
    }
    return out;
  }

  // ── deco 뱃지 1개 (좌상단 기준 x,y) ──
  async function drawDeco(ctx, deco, x, y, opts) {
    if (!deco) return;
    setHighQualityImageSmoothing(ctx);
    opts = opts || {};
    try { if (document.fonts && document.fonts.ready) await document.fonts.ready; } catch (e) {}
    const z = decoZoom(deco.scale);
    if (z !== 1) {
      ctx.save();
      ctx.translate(x, y);
      ctx.scale(z, z);
      await drawDeco(ctx, Object.assign({}, deco, { scale: 1 }), 0, 0, opts);
      ctx.restore();
      return;
    }
    if (deco.kind === 'color') {
      const overflow = deco.colors.length > 5;
      const cols = overflow ? deco.colors.slice(0, 4) : deco.colors;
      let cy = y;
      for (const c of cols) { ctx.fillStyle = c; rrect(ctx, x, cy, 20, 27, 10); ctx.fill(); cy += 27 + 4; }
      if (overflow) {
        ctx.fillStyle = '#c6c6c6'; rrect(ctx, x, cy, 20, 27, 10); ctx.fill();
        ctx.fillStyle = '#fff'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.font = '800 13px ' + KRFONT; ctx.fillText('+', x + 10, cy + 13.5);
      }
      return;
    }
    if (deco.kind === 'flag') {
      let cy = y;
      const items = normalizeFlagItems(deco.items, deco.count);
      for (let i = 0; i < items.length; i++) {
        const item = items[i];
        if (item.mode === 'image' && item.src) {
          try {
            const im = await loadImg(item.src);
            const box = 90;
            const sc = Math.min(box / im.naturalWidth, box / im.naturalHeight);
            const dw = im.naturalWidth * sc, dh = im.naturalHeight * sc;
            ctx.drawImage(im, x + 45 - dw / 2, cy + 45 - dh / 2, dw, dh);
          } catch (e) {}
        } else {
          ctx.fillStyle = PURPLE_FLAG; ctx.beginPath(); ctx.arc(x + 45, cy + 45, 45, 0, Math.PI * 2); ctx.fill();
          const lines = flagTextLines(item.text);
          const maxLen = Math.max.apply(null, lines.map((line) => line.length).concat(1));
          const fs = Math.max(11, Math.min(lines.length > 1 ? 17 : 22, 72 / (maxLen * 0.62)));
          const lh = fs * 1.12; const tc = cy + 45 - 2 - lh * (lines.length - 1) / 2;
          ctx.fillStyle = '#fff'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.font = '700 ' + fs + 'px ' + KRFONT;
          lines.forEach((line, idx) => ctx.fillText(line, x + 45, tc + lh * idx));
        }
        cy += 90 + 10;
      }
      return;
    }
    if (deco.kind === 'mark') {
      const label = deco.type === '다수구성' ? '+' : deco.type === 'OR' ? 'OR' : '구성';
      const W = deco.type === '다수구성' ? 30 : 38;
      let cy = y;
      for (let i = 0; i < (deco.count || 1); i++) {
        ctx.fillStyle = '#4E4CDB'; rrect(ctx, x, cy, W, 30, 15); ctx.fill();
        ctx.fillStyle = '#fff'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; ctx.font = '800 ' + (label.length > 2 ? 11 : 13) + 'px ' + KRFONT;
        ctx.fillText(label, x + W / 2, cy + 15);
        cy += 30 + 8;
      }
      return;
    }
    if (deco.kind === 'text') {
      ctx.fillStyle = PURPLE; ctx.beginPath(); ctx.arc(x + 45, y + 45, 45, 0, Math.PI * 2); ctx.fill();
      drawTextBadge(ctx, deco.text, x + 45, y + 45, 90);
      return;
    }
    if (deco.kind === 'image') {
      const W = 130, H = 130, HEAD = 40;
      ctx.save();
      ctx.fillStyle = '#fff'; rrect(ctx, x, y, W, H, 15); ctx.fill();
      // 헤더(보라) + 라벨
      ctx.save(); rrect(ctx, x, y, W, H, 15); ctx.clip();
      ctx.fillStyle = '#680ABA'; ctx.fillRect(x, y, W, HEAD);
      ctx.restore();
      const imgTypes = opts.imgTypes || [];
      const t = imgTypes.find((it) => it.id === deco.type) || imgTypes[0] || { label: deco.type || '' };
      const heading = deco.title != null ? String(deco.title).trim() || t.label : t.label;
      ctx.fillStyle = '#fff'; ctx.textAlign = 'center'; ctx.textBaseline = 'middle';
      const titleMaxW = t.icon ? 68 : W - 18;
      let titleFs = 20;
      ctx.font = '600 ' + titleFs + 'px ' + KRFONT;
      while (titleFs > 9 && ctx.measureText(heading || '').width > titleMaxW) {
        titleFs -= 1;
        ctx.font = '600 ' + titleFs + 'px ' + KRFONT;
      }
      if (t.icon) {
        const icx = x + 37, icy = y + HEAD / 2;
        ctx.fillStyle = '#38006A'; ctx.beginPath(); ctx.arc(icx, icy, 11, 0, Math.PI * 2); ctx.fill();
        ctx.strokeStyle = '#fff'; ctx.lineWidth = 2; ctx.lineCap = 'round';
        ctx.beginPath(); ctx.moveTo(icx, icy - 6); ctx.lineTo(icx, icy + 6); ctx.moveTo(icx - 6, icy); ctx.lineTo(icx + 6, icy); ctx.stroke();
        ctx.fillStyle = '#fff'; ctx.textAlign = 'left'; ctx.fillText(heading || '', x + 54, y + HEAD / 2);
      } else {
        ctx.fillText(heading || '', x + W / 2, y + HEAD / 2);
      }
      // 이미지 영역
      const ay = y + HEAD, aw = W, ah = H - HEAD;
      ctx.save(); rrect(ctx, x, y, W, H, 15); ctx.clip(); ctx.beginPath(); ctx.rect(x, ay, aw, ah); ctx.clip();
      ctx.fillStyle = '#fafafb'; ctx.fillRect(x, ay, aw, ah);
      if (deco.src) {
        try {
          const im = await loadImg(deco.src);
          const pos = deco.pos || { x: 50, y: 50 };
          const px = Math.max(0, Math.min(100, Number(pos.x) || 50)) / 100;
          const py = Math.max(0, Math.min(100, Number(pos.y) || 50)) / 100;
          const zoom = decoZoom(pos.zoom);
          if (deco.imgKind === 'nukki') {
            const pad = aw * 0.12, bw = aw - pad * 2, bh = ah - pad * 2;
            const sc = Math.min(bw / im.naturalWidth, bh / im.naturalHeight) * zoom;
            const dw = im.naturalWidth * sc, dh = im.naturalHeight * sc;
            ctx.drawImage(im, x + pad + (bw - dw) * px, ay + pad + (bh - dh) * py, dw, dh);
          } else {
            const sc = Math.min(aw / im.naturalWidth, ah / im.naturalHeight) * zoom;
            const dw = im.naturalWidth * sc, dh = im.naturalHeight * sc;
            ctx.drawImage(im, x + (aw - dw) * px, ay + (ah - dh) * py, dw, dh);
          }
        } catch (e) {}
      }
      ctx.restore();
      ctx.restore();
      return;
    }
  }

    // ── A/B/C/D 공통: 로고(우상단) + deco(가이드 기본 위치) ── (apOverlayEls 이식)
  // H1(776px): 최대3·maxRow=388(50%). 550: 최대3·maxRow=225(우측 여백 포함 절반선 침범 방지).
  async function drawStandard(ctx, data, opts) {
    setHighQualityImageSmoothing(ctx);
    data = data || {}; opts = opts || {};
    const logos = data.logos || [];
    const isH1 = ctx.canvas.width === 776;
    const logoTop = isH1 ? 20 : 40;
    const logoRight = isH1 ? 20 : 50;
    const logoMaxCount = 3;
    const logoMaxRow = isH1 ? 388 : 225;
    let logoBottom = logoTop;
    if (logos.length) {
      if (isH1) {
        // H1: base layout stays inside the right 50%; per-logo scale is top-right anchored.
        const rightBound = ctx.canvas.width - logoRight; // 756
        const minX = rightBound - logoMaxRow; // 50% guide line
        const gap = 10;
        const baseArr = logos.slice(0, logoMaxCount).map((g) => {
          const aspect = logoAspect(g.aspect);
          const orient = logoOrient(g);
          const baseH = orient === 'h' ? 20 : 60;
          return { url: g.url, baseH, baseW: baseH * aspect };
        });
        const totalBaseW = baseArr.reduce((s, l) => s + l.baseW, 0) + gap * (baseArr.length - 1);
        const k = totalBaseW > logoMaxRow ? logoMaxRow / totalBaseW : 1;
        const kGap = gap * k;
        const rightEdges = new Array(baseArr.length);
        let xR = rightBound;
        for (let i = baseArr.length - 1; i >= 0; i--) {
          rightEdges[i] = xR;
          xR = xR - baseArr[i].baseW * k - kGap;
        }
        const dims = baseArr.map((l, i) => {
          const g = logos[i];
          let w = l.baseW * k * logoScaleW(g);
          const h = l.baseH * k * logoScaleH(g);
          const maxW = rightEdges[i] - minX;
          if (w > maxW && maxW > 0) w = maxW;
          if (w < 1) w = 1;
          return { w, h };
        });
        const rowH = Math.max.apply(null, dims.map((l) => l.h));
        for (let i = baseArr.length - 1; i >= 0; i--) {
          const w = dims[i].w, h = dims[i].h, x = rightEdges[i] - w;
          try { const im = await loadImg(baseArr[i].url); ctx.drawImage(im, x, logoTop + (rowH - h) / 2, w, h); } catch (e) {}
        }
        logoBottom = logoTop + rowH;
      } else {
        // 550 A~D: 화면과 같은 단일 배치 결과를 사용한다.
        const row = window.LogoPlacement550.layout(logos);
        for (let i = row.items.length - 1; i >= 0; i--) {
          const item = row.items[i];
          try {
            const im = await loadImg(item.url);
            ctx.drawImage(im, item.x, item.y, item.w, item.h);
          } catch (e) {}
        }
        logoBottom = row.top + row.rowH;
      }
    }
    if (data.deco) {
      const pos = data.decoPos && typeof data.decoPos === 'object' ? data.decoPos : null;
      const def = isH1 && data.deco.kind === 'image'
        ? { x: ctx.canvas.width - logoRight - (data.deco.w || 90), y: ctx.canvas.height - 20 - (data.deco.h || 90) }
        : { x: ctx.canvas.width - logoRight - (data.deco.w || 90), y: logos.length ? logoBottom + 30 : logoTop };
      const h1Placement = isH1 && window.H1DecoPlacement;
      const resolved = h1Placement
        ? h1Placement.clamp(pos && (pos.x != null || pos.y != null) ? pos : h1Placement.defaultPosition(data.deco, logos.length ? logoBottom : null), data.deco)
        : { x: def.x, y: def.y };
      const top = resolved.y;
      const left = resolved.x;
      await drawDeco(ctx, data.deco, left, top, opts);
    }
  }

  window.BannerOverlay = { drawStandard, drawDeco, drawTextBadge, loadImg };
})();
