// ui.jsx — shared visual components (icons, photo placeholder, donut chart, badges)

const { useState, useEffect, useRef, useMemo } = React;

// ─────────────────────────────────────────────────────────────
// Icons — simple, line-based, all 20px viewBox
// ─────────────────────────────────────────────────────────────
function Icon({ name, size = 20, stroke = 'currentColor', strokeWidth = 1.6, fill = 'none' }) {
  const paths = {
    home: <><path d="M3 9l7-6 7 6v8a1 1 0 0 1-1 1h-3v-5H7v5H4a1 1 0 0 1-1-1V9z"/></>,
    list: <><path d="M7 5h10M7 10h10M7 15h10M3.5 5h.01M3.5 10h.01M3.5 15h.01"/></>,
    user: <><circle cx="10" cy="7" r="3"/><path d="M3.5 17c1.2-3 3.7-4.5 6.5-4.5s5.3 1.5 6.5 4.5"/></>,
    bell: <><path d="M10 3v1.2M5 8.5C5 6 7.2 4 10 4s5 2 5 4.5V11l1.5 2.5h-13L5 11V8.5z"/><path d="M8.5 14.5c.3.9 1.1 1.5 2 1.5s1.7-.6 2-1.5"/></>,
    camera: <><rect x="2.5" y="6" width="15" height="10" rx="2"/><path d="M7.5 6l1.5-2h2l1.5 2"/><circle cx="10" cy="11.5" r="2.8"/></>,
    image: <><rect x="2.5" y="3.5" width="15" height="13" rx="2"/><circle cx="7.5" cy="8" r="1.4"/><path d="M3 14l4-4 3 3 3-2 4 3.5"/></>,
    plus: <><path d="M10 4v12M4 10h12" strokeLinecap="round"/></>,
    check: <><path d="M4 10.5l3.5 3.5 8-8" strokeLinecap="round" strokeLinejoin="round"/></>,
    chev_r: <><path d="M7.5 4l6 6-6 6" strokeLinecap="round" strokeLinejoin="round"/></>,
    chev_l: <><path d="M12.5 4l-6 6 6 6" strokeLinecap="round" strokeLinejoin="round"/></>,
    close: <><path d="M5 5l10 10M15 5L5 15" strokeLinecap="round"/></>,
    search: <><circle cx="9" cy="9" r="5"/><path d="M13 13l3.5 3.5" strokeLinecap="round"/></>,
    filter: <><path d="M3 5h14M5.5 10h9M8 15h4" strokeLinecap="round"/></>,
    calendar: <><rect x="3" y="4.5" width="14" height="13" rx="2"/><path d="M3 8h14M7 2.5v3M13 2.5v3"/></>,
    clock: <><circle cx="10" cy="10" r="7"/><path d="M10 6v4l2.5 2" strokeLinecap="round"/></>,
    flag: <><path d="M5 3v14M5 4h9l-1.5 3L14 10H5"/></>,
    bolt: <><path d="M11 2L4 11h5l-1 7 7-9h-5l1-7z" strokeLinejoin="round"/></>,
    pin: <><path d="M10 2c-3 0-5 2-5 5 0 4 5 10 5 10s5-6 5-10c0-3-2-5-5-5z"/><circle cx="10" cy="7" r="1.8"/></>,
    sparkle: <><path d="M10 3v3M10 14v3M3 10h3M14 10h3M5 5l2 2M13 13l2 2M5 15l2-2M13 7l2-2"/></>,
    heart: <><path d="M10 16.5s-6-3.5-6-8.5a3.5 3.5 0 0 1 6-2.5 3.5 3.5 0 0 1 6 2.5c0 5-6 8.5-6 8.5z"/></>,
    arrow_r: <><path d="M4 10h12M11 5l5 5-5 5" strokeLinecap="round" strokeLinejoin="round"/></>,
    eye: <><path d="M2 10s3-5 8-5 8 5 8 5-3 5-8 5-8-5-8-5z"/><circle cx="10" cy="10" r="2.5"/></>,
    upload: <><path d="M10 14V4M5.5 8L10 4l4.5 4" strokeLinecap="round" strokeLinejoin="round"/><path d="M4 14v2a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1v-2"/></>,
    dot3: <><circle cx="5" cy="10" r="1.4"/><circle cx="10" cy="10" r="1.4"/><circle cx="15" cy="10" r="1.4"/></>,
    cog: <><circle cx="10" cy="10" r="2.5"/><path d="M10 2v2M10 16v2M2 10h2M16 10h2M4.5 4.5l1.5 1.5M14 14l1.5 1.5M4.5 15.5L6 14M14 6l1.5-1.5"/></>,
    layout: <><rect x="3" y="3" width="14" height="14" rx="2"/><path d="M3 8h14M9 8v9"/></>,
    chart: <><path d="M3 17V8M9 17V4M15 17v-6"/></>,
    globe: <><circle cx="10" cy="10" r="7"/><path d="M3 10h14M10 3c2.5 2.5 2.5 11.5 0 14M10 3c-2.5 2.5-2.5 11.5 0 14"/></>,
    edit: <><path d="M4 14.5V17h2.5L15 8.5 12.5 6 4 14.5z"/><path d="M11.5 7l2.5 2.5"/></>,
    refresh: <><path d="M3 10a7 7 0 0 1 12-5l2 2M17 4v3h-3"/><path d="M17 10a7 7 0 0 1-12 5l-2-2M3 16v-3h3"/></>,
    logout: <><path d="M13 6V4a1 1 0 0 0-1-1H4a1 1 0 0 0-1 1v12a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-2"/><path d="M8 10h9M14 7l3 3-3 3" strokeLinecap="round"/></>,
    // category icons
    cat_classroom: <><rect x="3" y="4" width="14" height="11" rx="1"/><path d="M3 11h14M7 15v2M13 15v2"/></>,
    cat_restroom: <><circle cx="6" cy="6" r="1.8"/><path d="M4 17v-5h4v5M6 11.5V12"/><circle cx="14" cy="6" r="1.8"/><path d="M12 17l1-5h2l1 5"/></>,
    cat_equipment: <><path d="M11 4l5 5-7 7-3-3 7-7zM4 13l3 3M8 4l-3 3 2 2 3-3"/></>,
    cat_cleanliness: <><path d="M14 3l3 3-8 8-3-3 8-8zM4 17l3-3 1 1-3 3-1-1z"/></>,
    cat_electricity: <><path d="M11 2L4 11h5l-1 7 7-9h-5l1-7z"/></>,
    cat_water: <><path d="M10 3s-5 6-5 10a5 5 0 0 0 10 0c0-4-5-10-5-10z"/></>,
    cat_safety: <><path d="M10 2L4 5v5c0 4 3 7 6 8 3-1 6-4 6-8V5l-6-3z"/></>,
    cat_common: <><circle cx="10" cy="10" r="6"/><path d="M4 10h12M10 4v12M5 6c2 2 8 2 10 0M5 14c2-2 8-2 10 0"/></>,
  };

  return (
    <svg width={size} height={size} viewBox="0 0 20 20" fill={fill} stroke={stroke}
      strokeWidth={strokeWidth} strokeLinecap="round" strokeLinejoin="round"
      style={{ flexShrink: 0, display: 'block' }}>
      {paths[name] || null}
    </svg>
  );
}

// Map category id → icon name
const CAT_ICONS = {
  classroom: 'cat_classroom',
  restroom: 'cat_restroom',
  equipment: 'cat_equipment',
  cleanliness: 'cat_cleanliness',
  electricity: 'cat_electricity',
  water: 'cat_water',
  safety: 'cat_safety',
  common: 'cat_common',
};

// ─────────────────────────────────────────────────────────────
// Photo placeholder — diagonal stripes + mono label
// ─────────────────────────────────────────────────────────────
function Photo({ hue = 270, label = '', tag = 'BEFORE', height = 160, dark, style = {}, after = false, url }) {
  const c1 = `oklch(0.50 0.22 ${hue})`;
  const c2 = `oklch(0.40 0.20 ${(hue + 30) % 360})`;
  const c3 = `oklch(0.62 0.20 ${(hue - 20 + 360) % 360})`;
  const bg = after
    ? `linear-gradient(135deg, oklch(0.50 0.18 155), oklch(0.42 0.16 170))`
    : `linear-gradient(135deg, ${c1}, ${c2} 50%, ${c3})`;

  return (
    <div className="bp-photo" style={{ height, '--ph-bg': bg, ...style }}>
      {url && (
        <img src={url} alt={label || tag} style={{
          position:'absolute', inset: 0, width:'100%', height:'100%',
          objectFit:'cover', zIndex: 0,
        }}/>
      )}
      <div className="lbl" style={{ zIndex: 2 }}>
        <span className="tag">
          {tag === 'BEFORE'
            ? <Icon name="camera" size={11}/>
            : <Icon name="check" size={11}/>
          }
          {tag}
        </span>
        {label && !url && <span style={{ marginTop: 4, fontSize: 9.5, opacity: 0.95 }}>{label}</span>}
      </div>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// Category chip
// ─────────────────────────────────────────────────────────────
function CategoryChip({ cat, lang = 'th', size = 'sm' }) {
  const big = size === 'lg';
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 6,
      padding: big ? '6px 12px' : '4px 9px',
      borderRadius: 999,
      background: cat.tint + '1A',
      color: cat.tint,
      fontSize: big ? 12 : 11,
      fontWeight: 500,
      whiteSpace: 'nowrap',
    }}>
      <span style={{
        width: big ? 18 : 14, height: big ? 18 : 14,
        borderRadius: big ? 5 : 4,
        background: cat.tint,
        display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
        color: '#fff',
      }}>
        <Icon name={CAT_ICONS[cat.id]} size={big ? 11 : 9} strokeWidth={2}/>
      </span>
      {cat[lang]}
    </span>
  );
}

// ─────────────────────────────────────────────────────────────
// Status pill
// ─────────────────────────────────────────────────────────────
function StatusPill({ status, lang = 'th', t }) {
  const map = {
    pending: { cls: 'pending', label: t.pending },
    'in-progress': { cls: 'progress', label: t.inProgress },
    resolved: { cls: 'resolved', label: t.resolved },
  };
  const m = map[status];
  return <span className={`bp-pill dot ${m.cls}`}>{m.label}</span>;
}

// ─────────────────────────────────────────────────────────────
// Donut chart — animated stroke-dasharray
// segments: [{ value, color }, …] (values sum to 100 or any total; we normalize)
// ─────────────────────────────────────────────────────────────
function Donut({ size = 220, stroke = 22, segments = [], center }) {
  const r = (size - stroke) / 2;
  const C = 2 * Math.PI * r;
  const total = segments.reduce((s, x) => s + x.value, 0) || 1;

  // animate from 0 to actual
  const [progress, setProgress] = useState(0);
  useEffect(() => {
    let raf, start;
    const dur = 900;
    const tick = (t) => {
      if (!start) start = t;
      const p = Math.min(1, (t - start) / dur);
      setProgress(easeOut(p));
      if (p < 1) raf = requestAnimationFrame(tick);
    };
    raf = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(raf);
  }, [segments.map(s => s.value).join(',')]);

  let cumulative = 0;
  const segs = segments.map((s, i) => {
    const frac = (s.value / total) * progress;
    const dash = C * frac;
    const gap = C - dash;
    const offset = -C * cumulative;
    cumulative += s.value / total;
    return { ...s, dash, gap, offset };
  });

  return (
    <div style={{ position: 'relative', width: size, height: size }}>
      <svg width={size} height={size} viewBox={`0 0 ${size} ${size}`} style={{ transform: 'rotate(-90deg)' }}>
        <defs>
          <linearGradient id="bp-donut-bg" x1="0" y1="0" x2="1" y2="1">
            <stop offset="0%"   stopColor="oklch(0.93 0.02 270)"/>
            <stop offset="100%" stopColor="oklch(0.95 0.02 290)"/>
          </linearGradient>
        </defs>
        <circle cx={size/2} cy={size/2} r={r} fill="none" stroke="url(#bp-donut-bg)" strokeWidth={stroke}/>
        {segs.map((s, i) => (
          <circle key={i}
            cx={size/2} cy={size/2} r={r}
            fill="none" stroke={s.color} strokeWidth={stroke}
            strokeLinecap="butt"
            strokeDasharray={`${s.dash} ${s.gap}`}
            strokeDashoffset={s.offset}
          />
        ))}
      </svg>
      {center && (
        <div style={{
          position: 'absolute', inset: 0,
          display: 'flex', flexDirection: 'column',
          alignItems: 'center', justifyContent: 'center', textAlign: 'center',
        }}>{center}</div>
      )}
    </div>
  );
}

function easeOut(t) { return 1 - Math.pow(1 - t, 3); }

// ─────────────────────────────────────────────────────────────
// Avatar with photo-upload — click/tap to pick an image (data URL)
// ─────────────────────────────────────────────────────────────
function AvatarUpload({ photo, name, onChange, size = 96, ring, light }) {
  const inputRef = useRef(null);
  const initial = (name || '?').trim().split('')[0];

  function pick(e) {
    const file = e.target.files && e.target.files[0];
    if (!file) return;
    const reader = new FileReader();
    reader.onload = ev => onChange(ev.target.result);
    reader.readAsDataURL(file);
    e.target.value = '';
  }

  return (
    <div style={{ position:'relative', width: size, height: size, flexShrink: 0 }}>
      <div style={{
        width: size, height: size, borderRadius:'50%',
        background: photo ? `url(${photo}) center/cover` : 'var(--bp-grad)',
        color:'#fff',
        display:'flex', alignItems:'center', justifyContent:'center',
        fontFamily:'Space Grotesk', fontSize: size * 0.4, fontWeight: 600,
        border: ring ? `4px solid ${ring}` : 'none',
        boxShadow: ring ? 'var(--bp-shadow)' : 'none',
        overflow:'hidden',
      }}>
        {!photo && initial}
      </div>
      <button onClick={() => inputRef.current && inputRef.current.click()} title="เปลี่ยนรูปโปรไฟล์" style={{
        position:'absolute', right: -2, bottom: -2,
        width: Math.max(28, size * 0.30), height: Math.max(28, size * 0.30),
        borderRadius:'50%',
        background: light ? 'rgba(255,255,255,0.95)' : 'var(--bp-grad)',
        color: light ? 'var(--bp-violet)' : '#fff',
        border:`2.5px solid var(--bp-surface)`,
        cursor:'pointer',
        display:'flex', alignItems:'center', justifyContent:'center',
        boxShadow:'0 4px 10px rgba(45,30,110,0.25)',
      }}>
        <Icon name="camera" size={Math.max(13, size * 0.14)} strokeWidth={1.8}/>
      </button>
      <input ref={inputRef} type="file" accept="image/*" onChange={pick} style={{ display:'none' }}/>
    </div>
  );
}

// Logo mark — small "Bp" lockup
function Logomark({ size = 32, light = false }) {
  return (
    <div style={{
      width: size, height: size, borderRadius: size * 0.28,
      background: light ? 'rgba(255,255,255,0.16)' : 'var(--bp-grad)',
      color: '#fff',
      display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
      fontFamily: 'Space Grotesk, sans-serif', fontWeight: 700,
      fontSize: size * 0.46, letterSpacing: '-0.04em',
      boxShadow: light ? 'none' : '0 6px 16px rgba(80, 50, 180, 0.28)',
      flexShrink: 0,
    }}>
      <span>B<span style={{ opacity: 0.7 }}>p</span></span>
    </div>
  );
}

Object.assign(window, {
  Icon, CAT_ICONS, Photo, CategoryChip, StatusPill, Donut, Logomark, easeOut, AvatarUpload,
});
