// templates.js — 프로 전용 디자인 템플릿 (10종)
// 각 템플릿은 Canvas 2D에 W×H(출력 해상도)로 그려지며, 폰트·좌표를 비율로 계산해
// 가로/세로/4K 등 어떤 해상도에도 자동으로 맞춰집니다. (window.TEMPLATES 전역)
(function () {
  const FONT = "'Pretendard','Apple SD Gothic Neo','Malgun Gothic',sans-serif";

  // ── 헬퍼 ──
  function rr(ctx, x, y, w, h, r) { 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(); }
  // 한 줄 텍스트가 maxW 안에 들어오도록 폰트 크기 축소
  function fit(ctx, text, maxW, maxPx, weight, fam) {
    let px = maxPx; ctx.font = `${weight} ${px}px ${fam || FONT}`;
    while (px > 8 && ctx.measureText(text).width > maxW) { px -= Math.max(1, Math.floor(px * 0.06)); ctx.font = `${weight} ${px}px ${fam || FONT}`; }
    return px;
  }
  // 자동 줄바꿈(공백/글자 단위, \n 지원)
  function wrap(ctx, text, maxW) {
    const out = []; let line = '';
    for (const ch of String(text)) {
      if (ch === '\n') { out.push(line); line = ''; continue; }
      const t = line + ch;
      if (ctx.measureText(t).width > maxW && line) { out.push(line); line = ch; } else line = t;
    }
    if (line || !out.length) out.push(line);
    return out;
  }
  function T(ctx, text, x, y, px, o) { o = o || {}; ctx.fillStyle = o.color || '#fff'; ctx.textAlign = o.align || 'center'; ctx.textBaseline = o.baseline || 'middle'; ctx.font = `${o.weight || '800'} ${px}px ${o.fam || FONT}`; if (o.spacing) { drawSpaced(ctx, text, x, y, o.spacing); } else ctx.fillText(text, x, y); }
  function drawSpaced(ctx, text, cx, y, sp) { const chars = [...String(text)]; let total = 0; for (const c of chars) total += ctx.measureText(c).width + sp; total -= sp; let x = cx - (ctx.textAlign === 'center' ? total / 2 : 0); const prev = ctx.textAlign; ctx.textAlign = 'left'; for (const c of chars) { ctx.fillText(c, x, y); x += ctx.measureText(c).width + sp; } ctx.textAlign = prev; }
  // 여러 줄 중앙 정렬 블록
  function block(ctx, text, cx, cy, maxW, px, o) {
    o = o || {}; ctx.font = `${o.weight || '800'} ${px}px ${o.fam || FONT}`;
    const lines = wrap(ctx, text, maxW); const lh = px * (o.lh || 1.22);
    let y = cy - (lines.length - 1) * lh / 2;
    for (const ln of lines) { T(ctx, ln, cx, y, px, o); y += lh; }
    return lines.length * lh;
  }
  function grad(ctx, W, H, c1, c2, dir) { const g = dir === 'h' ? ctx.createLinearGradient(0, 0, W, 0) : ctx.createLinearGradient(0, 0, 0, H); g.addColorStop(0, c1); g.addColorStop(1, c2); return g; }
  const isPortrait = (W, H) => H > W;

  // ── 템플릿 10종 ──
  const TEMPLATES = [
    { id: 'notice', name: '심플 공지', desc: '제목+부제, 좌측 강조바',
      fields: [{ key: 'title', label: '제목', def: '공지사항' }, { key: 'sub', label: '부제', def: '이용에 참고 부탁드립니다' }],
      draw(ctx, W, H, v) { const S = Math.min(W, H); ctx.fillStyle = '#0f2a5a'; ctx.fillRect(0, 0, W, H); ctx.fillStyle = grad(ctx, W, H, '#2f6bff', '#5aa2ff'); ctx.fillRect(0, 0, S * 0.06, H); T(ctx, 'NOTICE', W * 0.5, H * 0.2, S * 0.05, { color: '#9fc0ff', weight: '800', spacing: S * 0.02 }); block(ctx, v.title, W * 0.5, H * 0.46, W * 0.86, fit(ctx, v.title, W * 0.86, S * 0.17, '900'), { color: '#fff', weight: '900' }); block(ctx, v.sub, W * 0.5, H * 0.72, W * 0.82, S * 0.055, { color: '#bcd3ff', weight: '600', lh: 1.35 }); } },

    { id: 'sale', name: '세일·특가', desc: '큰 강조 문구 + 세일',
      fields: [{ key: 'top', label: '상단 문구', def: '여름 시즌 SALE' }, { key: 'big', label: '큰 문구', def: '최대 50%' }, { key: 'bot', label: '하단 문구', def: '8월 한 달 특가 이벤트' }],
      draw(ctx, W, H, v) { const S = Math.min(W, H); ctx.fillStyle = grad(ctx, W, H, '#ff5d5d', '#c81e1e'); ctx.fillRect(0, 0, W, H); ctx.fillStyle = 'rgba(255,255,255,.08)'; for (let i = -H; i < W; i += S * 0.14) { ctx.save(); ctx.translate(i, 0); ctx.rotate(0.5); ctx.fillRect(0, -H, S * 0.03, H * 3); ctx.restore(); } T(ctx, v.top, W * 0.5, H * 0.22, fit(ctx, v.top, W * 0.8, S * 0.08, '800'), { color: '#ffe0b8', weight: '800' }); T(ctx, v.big, W * 0.5, H * 0.5, fit(ctx, v.big, W * 0.9, S * 0.34, '900'), { color: '#fff', weight: '900' }); block(ctx, v.bot, W * 0.5, H * 0.78, W * 0.82, S * 0.06, { color: '#fff', weight: '700', lh: 1.3 }); } },

    { id: 'event', name: '이벤트 안내', desc: '제목+날짜+장소',
      fields: [{ key: 'title', label: '행사명', def: '가을 문화 축제' }, { key: 'date', label: '일시', def: '2026. 9. 20 (토) 14:00' }, { key: 'place', label: '장소', def: '시민 광장 특설무대' }],
      draw(ctx, W, H, v) { const S = Math.min(W, H); ctx.fillStyle = '#111827'; ctx.fillRect(0, 0, W, H); ctx.fillStyle = grad(ctx, W, H, '#7c3aed', '#2f6bff'); ctx.fillRect(0, H * 0.14, W, S * 0.02); ctx.fillRect(0, H * 0.86 - S * 0.02, W, S * 0.02); T(ctx, 'EVENT', W * 0.5, H * 0.26, S * 0.055, { color: '#a78bfa', weight: '800', spacing: S * 0.03 }); block(ctx, v.title, W * 0.5, H * 0.44, W * 0.86, fit(ctx, v.title, W * 0.86, S * 0.16, '900'), { color: '#fff', weight: '900' }); T(ctx, '📅 ' + v.date, W * 0.5, H * 0.65, fit(ctx, '📅 ' + v.date, W * 0.82, S * 0.06, '700'), { color: '#e5e7eb', weight: '700' }); T(ctx, '📍 ' + v.place, W * 0.5, H * 0.74, fit(ctx, '📍 ' + v.place, W * 0.82, S * 0.06, '700'), { color: '#cbd5e1', weight: '600' }); } },

    { id: 'hours', name: '영업 안내', desc: '제목 + 안내 2줄',
      fields: [{ key: 'title', label: '제목', def: '영업시간 안내' }, { key: 'l1', label: '안내 1', def: '평일 09:00 ~ 21:00' }, { key: 'l2', label: '안내 2', def: '주말·공휴일 10:00 ~ 18:00' }],
      draw(ctx, W, H, v) { const S = Math.min(W, H); ctx.fillStyle = '#f8fafc'; ctx.fillRect(0, 0, W, H); ctx.fillStyle = grad(ctx, W, H, '#2f6bff', '#0e4ed8'); ctx.fillRect(0, 0, W, H * 0.26); T(ctx, v.title, W * 0.5, H * 0.13, fit(ctx, v.title, W * 0.86, S * 0.11, '900'), { color: '#fff', weight: '900' }); function line(txt, y) { ctx.fillStyle = '#fff'; rr(ctx, W * 0.1, y - S * 0.055, W * 0.8, S * 0.11, S * 0.02); ctx.fill(); ctx.strokeStyle = '#e2e8f0'; ctx.lineWidth = S * 0.004; ctx.stroke(); T(ctx, txt, W * 0.5, y, fit(ctx, txt, W * 0.72, S * 0.058, '700'), { color: '#0f172a', weight: '700' }); } line(v.l1, H * 0.5); line(v.l2, H * 0.68); T(ctx, 'BUSINESS HOURS', W * 0.5, H * 0.86, S * 0.035, { color: '#94a3b8', weight: '700', spacing: S * 0.015 }); } },

    { id: 'welcome', name: '환영 인사', desc: 'WELCOME + 문구',
      fields: [{ key: 'sub', label: '상단 영문', def: 'WELCOME' }, { key: 'main', label: '문구', def: '방문을 진심으로 환영합니다' }],
      draw(ctx, W, H, v) { const S = Math.min(W, H); ctx.fillStyle = grad(ctx, W, H, '#0a2b56', '#2f6bff'); ctx.fillRect(0, 0, W, H); ctx.strokeStyle = 'rgba(255,255,255,.25)'; ctx.lineWidth = S * 0.006; rr(ctx, W * 0.06, H * 0.08, W * 0.88, H * 0.84, S * 0.04); ctx.stroke(); T(ctx, v.sub, W * 0.5, H * 0.34, fit(ctx, v.sub, W * 0.8, S * 0.13, '900'), { color: '#bcd3ff', weight: '900', spacing: S * 0.02 }); block(ctx, v.main, W * 0.5, H * 0.6, W * 0.8, fit(ctx, v.main, W * 0.8, S * 0.085, '700'), { color: '#fff', weight: '700', lh: 1.3 }); } },

    { id: 'product', name: '신상품 NEW', desc: 'NEW 뱃지 + 상품·가격',
      fields: [{ key: 'name', label: '상품명', def: '시그니처 아메리카노' }, { key: 'price', label: '가격', def: '4,500원' }, { key: 'sub', label: '부제', def: '갓 볶은 원두로 내린 진한 풍미' }],
      draw(ctx, W, H, v) { const S = Math.min(W, H); ctx.fillStyle = '#fffdf7'; ctx.fillRect(0, 0, W, H); ctx.fillStyle = grad(ctx, W, H, '#18b26b', '#0d9488'); ctx.beginPath(); ctx.arc(W * 0.8, H * 0.16, S * 0.11, 0, 7); ctx.fill(); T(ctx, 'NEW', W * 0.8, H * 0.16, S * 0.06, { color: '#fff', weight: '900' }); block(ctx, v.name, W * 0.5, H * 0.45, W * 0.86, fit(ctx, v.name, W * 0.86, S * 0.14, '900'), { color: '#0f172a', weight: '900' }); T(ctx, v.price, W * 0.5, H * 0.66, fit(ctx, v.price, W * 0.7, S * 0.15, '900'), { color: '#c81e1e', weight: '900' }); block(ctx, v.sub, W * 0.5, H * 0.82, W * 0.82, S * 0.05, { color: '#6b7280', weight: '600', lh: 1.3 }); } },

    { id: 'safety', name: '안전·주의', desc: '경고 줄무늬 + 안내',
      fields: [{ key: 'title', label: '제목', def: '안전 수칙 안내' }, { key: 'body', label: '내용', def: '공사 중입니다. 통행 시 주의하세요.' }],
      draw(ctx, W, H, v) { const S = Math.min(W, H); ctx.fillStyle = '#fffbeb'; ctx.fillRect(0, 0, W, H); function stripe(y0, h) { for (let i = -H; i < W; i += S * 0.12) { ctx.fillStyle = ((i / (S * 0.12)) | 0) % 2 ? '#111827' : '#f59e0b'; ctx.save(); ctx.beginPath(); ctx.rect(0, y0, W, h); ctx.clip(); ctx.translate(i, y0); ctx.rotate(0.5); ctx.fillRect(0, -h, S * 0.06, h * 3); ctx.restore(); } } stripe(0, S * 0.05); stripe(H - S * 0.05, S * 0.05); T(ctx, '⚠', W * 0.5, H * 0.28, S * 0.18, { color: '#f59e0b', weight: '900' }); block(ctx, v.title, W * 0.5, H * 0.5, W * 0.86, fit(ctx, v.title, W * 0.86, S * 0.13, '900'), { color: '#111827', weight: '900' }); block(ctx, v.body, W * 0.5, H * 0.72, W * 0.84, S * 0.056, { color: '#374151', weight: '600', lh: 1.35 }); } },

    { id: 'today', name: '오늘의 안내', desc: '큰 날짜 + 문구',
      fields: [{ key: 'date', label: '날짜/요일', def: '8월 15일 (금)' }, { key: 'body', label: '문구', def: '광복절 휴무입니다' }],
      draw(ctx, W, H, v) { const S = Math.min(W, H); ctx.fillStyle = grad(ctx, W, H, '#111827', '#1f2937'); ctx.fillRect(0, 0, W, H); T(ctx, 'TODAY', W * 0.5, H * 0.2, S * 0.045, { color: '#60a5fa', weight: '800', spacing: S * 0.02 }); block(ctx, v.date, W * 0.5, H * 0.42, W * 0.86, fit(ctx, v.date, W * 0.86, S * 0.16, '900'), { color: '#fff', weight: '900' }); ctx.fillStyle = '#2f6bff'; rr(ctx, W * 0.3, H * 0.58, W * 0.4, S * 0.008, S * 0.004); ctx.fill(); block(ctx, v.body, W * 0.5, H * 0.72, W * 0.82, fit(ctx, v.body, W * 0.82, S * 0.08, '700'), { color: '#e5e7eb', weight: '700', lh: 1.3 }); } },

    { id: 'center', name: '센터 메시지', desc: '한 문구 크게',
      fields: [{ key: 'msg', label: '문구', def: '함께해 주셔서\n감사합니다' }],
      draw(ctx, W, H, v) { const S = Math.min(W, H); ctx.fillStyle = grad(ctx, W, H, '#6d28d9', '#2f6bff'); ctx.fillRect(0, 0, W, H); ctx.fillStyle = 'rgba(255,255,255,.08)'; ctx.beginPath(); ctx.arc(W * 0.15, H * 0.85, S * 0.2, 0, 7); ctx.arc(W * 0.88, H * 0.15, S * 0.16, 0, 7); ctx.fill(); block(ctx, v.msg, W * 0.5, H * 0.5, W * 0.84, fit(ctx, (v.msg || '').split('\n').sort((a, b) => b.length - a.length)[0] || v.msg, W * 0.84, S * 0.16, '900'), { color: '#fff', weight: '900', lh: 1.2 }); } },

    { id: 'banner', name: '가로 현수막', desc: '긴 한 줄 + 서브',
      fields: [{ key: 'big', label: '큰 문구', def: '신장개업 감사 대잔치' }, { key: 'sub', label: '서브 문구', def: '전 품목 20% 할인 · 사은품 증정' }],
      draw(ctx, W, H, v) { const S = Math.min(W, H); ctx.fillStyle = grad(ctx, W, H, '#2f6bff', '#6d28d9', 'h'); ctx.fillRect(0, 0, W, H); ctx.fillStyle = 'rgba(255,255,255,.1)'; ctx.fillRect(0, H * 0.5 - S * 0.005, W, S * 0.01); T(ctx, v.big, W * 0.5, H * 0.4, fit(ctx, v.big, W * 0.92, S * 0.2, '900'), { color: '#fff', weight: '900' }); T(ctx, v.sub, W * 0.5, H * 0.66, fit(ctx, v.sub, W * 0.88, S * 0.075, '700'), { color: '#dbeafe', weight: '700' }); } },
  ];

  window.TEMPLATES = TEMPLATES;
  // 지정 템플릿을 캔버스에 렌더 (values 없으면 기본값)
  window.renderTemplate = function (canvas, tpl, values, W, H) {
    canvas.width = W; canvas.height = H;
    const ctx = canvas.getContext('2d');
    const v = {}; (tpl.fields || []).forEach((f) => { v[f.key] = (values && values[f.key] != null && values[f.key] !== '') ? values[f.key] : f.def; });
    ctx.save(); tpl.draw(ctx, W, H, v); ctx.restore();
  };
})();
