/* pedal-ui.jsx — primitivos visuais partilhados do PEDAL */

// ── Ícones (geometria simples apenas) ────────────────────────────────
function Icon({ name, size = 20, color = 'currentColor', stroke = 2 }) {
  const p = { width: size, height: size, viewBox: '0 0 24 24', fill: 'none',
    stroke: color, strokeWidth: stroke, strokeLinecap: 'round', strokeLinejoin: 'round' };
  switch (name) {
    case 'check':   return <svg {...p}><path d="M4 12.5l5 5L20 6" /></svg>;
    case 'send':    return <svg {...p}><path d="M5 12h13M12 5l7 7-7 7" /></svg>;
    case 'chat':    return <svg {...p}><path d="M4 5h16v11H9l-5 4z" /></svg>;
    case 'book':    return <svg {...p}><path d="M5 4h11a3 3 0 013 3v13H8a3 3 0 00-3 3z" /><path d="M5 4v19" /></svg>;
    case 'route':   return <svg {...p}><circle cx="6" cy="18" r="2.5" /><circle cx="18" cy="6" r="2.5" /><path d="M8.5 18H14a3 3 0 000-6H10a3 3 0 010-6h5.5" /></svg>;
    case 'pin':     return <svg {...p}><path d="M12 21s7-6.2 7-11a7 7 0 10-14 0c0 4.8 7 11 7 11z" /><circle cx="12" cy="10" r="2.4" /></svg>;
    case 'clock':   return <svg {...p}><circle cx="12" cy="12" r="8.5" /><path d="M12 7.5V12l3 2" /></svg>;
    case 'shield':  return <svg {...p}><path d="M12 3l7 3v6c0 4.5-3 7.5-7 9-4-1.5-7-4.5-7-9V6z" /><path d="M9 12l2 2 4-4" /></svg>;
    case 'user':    return <svg {...p}><circle cx="12" cy="8" r="3.5" /><path d="M5 20c1.2-3.6 4-5 7-5s5.8 1.4 7 5" /></svg>;
    case 'play':    return <svg {...p} fill={color} stroke="none"><path d="M7 5l12 7-12 7z" /></svg>;
    case 'lock':    return <svg {...p}><rect x="5" y="11" width="14" height="9" rx="2" /><path d="M8 11V8a4 4 0 018 0v3" /></svg>;
    case 'bell':    return <svg {...p}><path d="M6 9a6 6 0 0112 0c0 5 2 6 2 6H4s2-1 2-6z" /><path d="M10 20a2 2 0 004 0" /></svg>;
    case 'doc':     return <svg {...p}><path d="M7 3h7l4 4v14H7z" /><path d="M14 3v4h4" /><path d="M10 13h5M10 16h5" /></svg>;
    case 'phone':   return <svg {...p}><path d="M6 4h4l2 5-3 2a11 11 0 005 5l2-3 5 2v4a2 2 0 01-2 2A16 16 0 014 6a2 2 0 012-2z" /></svg>;
    case 'arrow':   return <svg {...p}><path d="M5 12h14M13 6l6 6-6 6" /></svg>;
    case 'heart':   return <svg {...p}><path d="M12 20s-7-4.6-9.2-9C1.3 8 3 4.5 6.5 4.5 9 4.5 12 7 12 7s3-2.5 5.5-2.5C21 4.5 22.7 8 21.2 11 19 15.4 12 20 12 20z" /></svg>;
    case 'sparkle': return <svg {...p}><path d="M12 3v6M12 15v6M3 12h6M15 12h6" /></svg>;
    case 'people':  return <svg {...p}><circle cx="9" cy="8" r="3" /><path d="M3 19c.8-3 3.2-4.5 6-4.5S14.2 16 15 19" /><path d="M16 5.5a3 3 0 010 5.8M18 19c-.3-2-1.2-3.3-2.5-4" /></svg>;
    case 'map':        return <svg {...p}><path d="M3 7l5 2 8-4 5 2v12l-5-2-8 4-5-2z" /><path d="M8 9v10M16 5v10" /></svg>;
    case 'mortarboard': return <svg {...p}><path d="M2 10l10-5 10 5-10 5z" /><path d="M6 12v5c3 3 9 3 12 0v-5" /><path d="M22 10v6" /></svg>;
    case 'search':  return <svg {...p}><circle cx="11" cy="11" r="7" /><path d="M21 21l-4.3-4.3" /></svg>;
    case 'eye':     return <svg {...p}><path d="M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7z" /><circle cx="12" cy="12" r="3" /></svg>;
    case 'eye-off': return <svg {...p}><path d="M2 12s3.5-7 10-7c2 0 3.7.6 5.1 1.4M22 12s-3.5 7-10 7c-2 0-3.7-.6-5.1-1.4" /><path d="M9.9 9.9a3 3 0 004.2 4.2" /><path d="M3 3l18 18" /></svg>;
    case 'calendar': return <svg {...p}><rect x="4" y="5" width="16" height="16" rx="2" /><path d="M8 3v4M16 3v4M4 10h16" /></svg>;
    case 'restart': return <svg {...p}><path d="M3 4v6h6" /><path d="M4.2 15a8.5 8.5 0 102-9L3 9.2" /></svg>;
    default: return null;
  }
}

// ── Avatar PEDAL: roda de bicicleta (círculo + cubo + raios) ─────────
function PedalMark({ size = 40, color = 'var(--primary)', bg = '#fff' }) {
  const s = size, c = s / 2, r = s * 0.36;
  const spokes = [];
  for (let i = 0; i < 8; i++) {
    const a = (Math.PI / 4) * i;
    spokes.push(<line key={i} x1={c} y1={c} x2={c + r * Math.cos(a)} y2={c + r * Math.sin(a)}
      stroke={color} strokeWidth={s * 0.025} strokeLinecap="round" opacity="0.55" />);
  }
  return (
    <svg width={s} height={s} viewBox={`0 0 ${s} ${s}`}>
      <circle cx={c} cy={c} r={r} fill="none" stroke={color} strokeWidth={s * 0.07} />
      {spokes}
      <circle cx={c} cy={c} r={s * 0.085} fill={color} />
    </svg>
  );
}

function Avatar({ size = 38 }) {
  return (
    <div style={{
      width: size, height: size, borderRadius: '50%', flexShrink: 0,
      background: 'var(--primary)', display: 'flex', alignItems: 'center', justifyContent: 'center',
      boxShadow: '0 2px 6px rgba(0,0,0,0.12)',
    }}>
      <PedalMark size={size * 0.74} color="#fff" />
    </div>
  );
}

// ── Indicador "a escrever" ───────────────────────────────────────────
function TypingDots() {
  return (
    <div className="pedal-typing" style={{
      display: 'inline-flex', gap: 5, alignItems: 'center',
      background: 'var(--surface)', border: '1px solid var(--line)',
      padding: '13px 16px', borderRadius: '4px 18px 18px 18px',
    }}>
      {[0, 1, 2].map((i) => (
        <span key={i} style={{
          width: 8, height: 8, borderRadius: '50%', background: 'var(--ink-soft)',
          opacity: 0.5, animation: `pedalBounce 1.2s ${i * 0.18}s infinite ease-in-out`,
        }} />
      ))}
    </div>
  );
}

// ── Quick replies ────────────────────────────────────────────────────
function QuickReplies({ options, onPick }) {
  return (
    <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8, justifyContent: 'flex-start', marginTop: 4, paddingLeft: 46 }}>
      {options.map((o) => {
        const label = typeof o === 'string' ? o : o.label;
        const acc = typeof o === 'object' ? o.accent : null;
        const fill = acc === 'fill';
        return (
          <button key={label} className="pedal-chip-btn" onClick={() => onPick(o)}
            style={{
              border: `1.5px solid ${fill ? 'var(--primary)' : acc ? 'var(--primary)' : 'var(--line)'}`,
              color: fill ? '#fff' : acc ? 'var(--primary)' : 'var(--ink)',
              background: fill ? 'var(--primary)' : 'var(--surface)',
              fontWeight: fill || acc ? 700 : 600,
            }}>
            {label}
          </button>
        );
      })}
    </div>
  );
}

// ── Placeholder de imagem (riscado + legenda monospace) ──────────────
function Placeholder({ label, height = 132, radius = 14 }) {
  return (
    <div style={{
      height, borderRadius: radius, width: '100%',
      background: 'repeating-linear-gradient(135deg, var(--ph-a) 0 11px, var(--ph-b) 11px 22px)',
      border: '1px solid var(--line)', display: 'flex', alignItems: 'center', justifyContent: 'center',
    }}>
      <span style={{
        font: '600 11px/1.3 ui-monospace, "SF Mono", Menlo, monospace',
        letterSpacing: 0.4, color: 'var(--ink-soft)', textTransform: 'uppercase',
        background: 'var(--app-bg)', padding: '4px 8px', borderRadius: 6, textAlign: 'center',
      }}>{label}</span>
    </div>
  );
}

// ── Barra de progresso ───────────────────────────────────────────────
function ProgressBar({ value, total, color = 'var(--accent)' }) {
  const pct = total ? Math.round((value / total) * 100) : 0;
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
      <div style={{ flex: 1, height: 8, borderRadius: 99, background: 'var(--line)', overflow: 'hidden' }}>
        <div style={{ width: `${pct}%`, height: '100%', background: color, borderRadius: 99, transition: 'width .5s cubic-bezier(.4,0,.2,1)' }} />
      </div>
      <span style={{ font: '700 12px var(--ui)', color: 'var(--ink-soft)', minWidth: 34, textAlign: 'right' }}>{pct}%</span>
    </div>
  );
}

// ── Pill / badge ─────────────────────────────────────────────────────
function Pill({ children, tone = 'neutral' }) {
  const tones = {
    neutral: { bg: 'var(--app-bg)', fg: 'var(--ink-soft)', bd: 'var(--line)' },
    green:   { bg: 'var(--accent-soft)', fg: 'var(--accent-deep)', bd: 'transparent' },
    amber:   { bg: 'var(--warn-soft)', fg: 'var(--warn-deep)', bd: 'transparent' },
    red:     { bg: 'var(--danger-soft)', fg: 'var(--danger)', bd: 'transparent' },
  }[tone];
  return (
    <span style={{
      font: '700 11px var(--ui)', letterSpacing: 0.2, padding: '4px 9px', borderRadius: 99,
      background: tones.bg, color: tones.fg, border: `1px solid ${tones.bd}`,
      display: 'inline-flex', alignItems: 'center', gap: 5, whiteSpace: 'nowrap',
    }}>{children}</span>
  );
}

// ── Campo de data em formato português (dd/mm/aaaa) ─────────────────
// Substitui <input type="date">: a apresentação do input nativo segue o
// idioma do browser/SO (mm/dd/yyyy em browsers em inglês) e não pode ser
// forçada a pt-PT. Aceita escrita com máscara automática e traz um
// calendário próprio em português. `value`/`onChange` continuam a falar
// ISO 'YYYY-MM-DD' ('' enquanto a data estiver incompleta ou for
// inválida), pelo que o código à volta não precisa de mudar.
const MESES_PT = ['janeiro', 'fevereiro', 'março', 'abril', 'maio', 'junho', 'julho', 'agosto', 'setembro', 'outubro', 'novembro', 'dezembro'];

function DateInputPT({ value, onChange, inputRef, style, ...rest }) {
  const isoToText = (iso) => {
    if (!/^\d{4}-\d{2}-\d{2}$/.test(iso || '')) return '';
    const [y, m, d] = iso.split('-');
    return `${d}/${m}/${y}`;
  };
  const textToIso = (text) => {
    const m = /^(\d{2})\/(\d{2})\/(\d{4})$/.exec(text);
    if (!m) return '';
    const iso = `${m[3]}-${m[2]}-${m[1]}`;
    const d = new Date(iso + 'T00:00:00');
    return !isNaN(d) && d.getDate() === Number(m[1]) && d.getMonth() + 1 === Number(m[2]) ? iso : '';
  };
  const [text, setText] = React.useState(isoToText(value));
  // Sincroniza quando o valor muda por fora (reset do formulário, valor por defeito)
  React.useEffect(() => {
    setText((prev) => (textToIso(prev) === (value || '') ? prev : isoToText(value)));
  }, [value]);
  const handleChange = (raw) => {
    const digits = raw.replace(/\D/g, '').slice(0, 8);
    const t = digits.length > 4 ? `${digits.slice(0, 2)}/${digits.slice(2, 4)}/${digits.slice(4)}`
      : digits.length > 2 ? `${digits.slice(0, 2)}/${digits.slice(2)}` : digits;
    setText(t);
    onChange(textToIso(t));
  };

  // Calendário: abre no mês da data escolhida (ou no atual), fecha com
  // Escape ou clique fora. A semana começa à segunda-feira.
  const [open, setOpen] = React.useState(false);
  const today = new Date();
  const viewOf = () => {
    const d = /^\d{4}-\d{2}-\d{2}$/.test(value || '') ? new Date(value + 'T00:00:00') : today;
    return { y: d.getFullYear(), m: d.getMonth() };
  };
  const [view, setView] = React.useState(viewOf);
  const wrapRef = React.useRef(null);
  React.useEffect(() => {
    if (!open) return undefined;
    const onDoc = (e) => { if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false); };
    const onKey = (e) => { if (e.key === 'Escape') setOpen(false); };
    document.addEventListener('mousedown', onDoc);
    document.addEventListener('keydown', onKey);
    return () => { document.removeEventListener('mousedown', onDoc); document.removeEventListener('keydown', onKey); };
  }, [open]);

  const toggle = () => { if (!open) setView(viewOf()); setOpen((o) => !o); };
  const nav = (delta) => setView((v) => { const d = new Date(v.y, v.m + delta, 1); return { y: d.getFullYear(), m: d.getMonth() }; });
  const pick = (day) => {
    const iso = `${view.y}-${String(view.m + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
    setText(isoToText(iso));
    onChange(iso);
    setOpen(false);
  };

  const daysInMonth = new Date(view.y, view.m + 1, 0).getDate();
  const firstOffset = (new Date(view.y, view.m, 1).getDay() + 6) % 7;
  const isToday = (day) => view.y === today.getFullYear() && view.m === today.getMonth() && day === today.getDate();
  const isSelected = (day) => value === `${view.y}-${String(view.m + 1).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
  const years = [];
  for (let y = today.getFullYear() + 2; y >= today.getFullYear() - 106; y -= 1) years.push(y);

  const navBtnStyle = { border: 'none', background: 'none', cursor: 'pointer', color: 'var(--ink-soft)', font: '700 17px var(--ui)', padding: '2px 8px', borderRadius: 8, lineHeight: 1 };
  const selStyle = { font: '600 12.5px var(--ui)', color: 'var(--ink)', background: 'var(--app-bg)', border: '1px solid var(--line)', borderRadius: 8, padding: '5px 4px', outline: 'none', cursor: 'pointer', minWidth: 0 };

  return (
    <div ref={wrapRef} style={{ position: 'relative', ...style }}>
      <input {...rest} ref={inputRef} type="text" inputMode="numeric" placeholder="dd/mm/aaaa"
        maxLength={10} value={text} onChange={(e) => handleChange(e.target.value)}
        style={{ paddingRight: 40 }} />
      <button type="button" aria-label="Abrir calendário" aria-expanded={open} onClick={toggle}
        style={{ position: 'absolute', right: 5, top: '50%', transform: 'translateY(-50%)', border: 'none', background: 'none', padding: 6, cursor: 'pointer', color: open ? 'var(--primary)' : 'var(--ink-soft)', display: 'flex' }}>
        <Icon name="calendar" size={17} />
      </button>
      {open && (
        <div role="dialog" aria-label="Calendário"
          style={{ position: 'absolute', top: 'calc(100% + 6px)', left: 0, zIndex: 60, background: 'var(--surface)', border: '1px solid var(--line)', borderRadius: 14, boxShadow: '0 16px 40px rgba(0,0,0,.14)', padding: 12, width: 268 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 4, marginBottom: 9 }}>
            <button type="button" aria-label="Mês anterior" onClick={() => nav(-1)} style={navBtnStyle}>‹</button>
            <select aria-label="Mês" value={view.m} onChange={(e) => setView((v) => ({ ...v, m: Number(e.target.value) }))} style={{ ...selStyle, flex: 1 }}>
              {MESES_PT.map((n, i) => <option key={n} value={i}>{n}</option>)}
            </select>
            <select aria-label="Ano" value={view.y} onChange={(e) => setView((v) => ({ ...v, y: Number(e.target.value) }))} style={selStyle}>
              {years.map((y) => <option key={y} value={y}>{y}</option>)}
            </select>
            <button type="button" aria-label="Mês seguinte" onClick={() => nav(1)} style={navBtnStyle}>›</button>
          </div>
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(7, 1fr)', gap: 2 }}>
            {['S', 'T', 'Q', 'Q', 'S', 'S', 'D'].map((d, i) => (
              <div key={i} style={{ font: '700 10.5px var(--ui)', color: 'var(--ink-soft)', textAlign: 'center', padding: '3px 0' }}>{d}</div>
            ))}
            {Array.from({ length: firstOffset }, (_, i) => <div key={`v${i}`} />)}
            {Array.from({ length: daysInMonth }, (_, i) => {
              const day = i + 1;
              const sel = isSelected(day);
              return (
                <button key={day} type="button" onClick={() => pick(day)}
                  style={{
                    font: `${sel || isToday(day) ? 700 : 500} 13px var(--ui)`,
                    color: sel ? '#fff' : isToday(day) ? 'var(--primary-deep)' : 'var(--ink)',
                    background: sel ? 'var(--primary)' : isToday(day) ? 'var(--primary-soft)' : 'none',
                    border: 'none', borderRadius: 9, height: 32, cursor: 'pointer',
                  }}>{day}</button>
              );
            })}
          </div>
        </div>
      )}
    </div>
  );
}

// ── Campo de hora em formato português (24h, hh:mm) ─────────────────
// Substitui <input type="time">: o input nativo segue o idioma do
// browser/SO (AM/PM em browsers em inglês) e escrever nele é pouco
// prático. Aceita escrita com máscara automática ("930" → 09:30; "14"
// → 14:00 ao sair do campo) e traz uma lista de horas de 30 em 30
// minutos. `value`/`onChange` continuam a falar 'HH:MM' em 24h (''
// enquanto a hora estiver incompleta ou for inválida), pelo que o
// código à volta não precisa de mudar.
function TimeInputPT({ value, onChange, inputRef, style, ...rest }) {
  const textToValue = (text) => (/^([01]\d|2[0-3]):[0-5]\d$/.test(text || '') ? text : '');
  const [text, setText] = React.useState(value || '');
  // Sincroniza quando o valor muda por fora (reset do formulário, valor por defeito)
  React.useEffect(() => {
    setText((prev) => (textToValue(prev) === (value || '') ? prev : (value || '')));
  }, [value]);
  const handleChange = (raw) => {
    let digits = raw.replace(/\D/g, '');
    if (digits && Number(digits[0]) > 2) digits = '0' + digits; // 3–9 só pode ser hora de um dígito
    digits = digits.slice(0, 4);
    const t = digits.length > 2 ? `${digits.slice(0, 2)}:${digits.slice(2)}` : digits;
    setText(t);
    onChange(textToValue(t));
  };
  // Ao sair do campo, completa uma hora certa escrita a meio: "14" → "14:00"
  const handleBlur = () => {
    const m = /^([01]\d|2[0-3]):?$/.exec(text);
    if (m) { const t = `${m[1]}:00`; setText(t); onChange(t); }
  };

  // Lista de horas: fecha com Escape ou clique fora; abre centrada na
  // hora escolhida (ou nas 10:00, início habitual dos passeios).
  const [open, setOpen] = React.useState(false);
  const wrapRef = React.useRef(null);
  const listRef = React.useRef(null);
  React.useEffect(() => {
    if (!open) return undefined;
    const onDoc = (e) => { if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false); };
    const onKey = (e) => { if (e.key === 'Escape') setOpen(false); };
    document.addEventListener('mousedown', onDoc);
    document.addEventListener('keydown', onKey);
    return () => { document.removeEventListener('mousedown', onDoc); document.removeEventListener('keydown', onKey); };
  }, [open]);
  React.useEffect(() => {
    if (!open || !listRef.current) return;
    const target = listRef.current.querySelector('[aria-selected="true"]') || listRef.current.querySelector('[data-time="10:00"]');
    if (target) target.scrollIntoView({ block: 'center' });
  }, [open]);

  const options = [];
  for (let h = 7; h <= 21; h += 1) for (const mm of ['00', '30']) options.push(`${String(h).padStart(2, '0')}:${mm}`);
  const pick = (t) => { setText(t); onChange(t); setOpen(false); };

  return (
    <div ref={wrapRef} style={{ position: 'relative', minWidth: 0, ...style }}>
      <input {...rest} ref={inputRef} type="text" inputMode="numeric" placeholder="hh:mm" size={5}
        maxLength={5} value={text} onChange={(e) => handleChange(e.target.value)} onBlur={handleBlur}
        style={{ paddingRight: 34 }} />
      <button type="button" aria-label="Escolher hora" aria-expanded={open} onClick={() => setOpen((o) => !o)}
        style={{ position: 'absolute', right: 5, top: '50%', transform: 'translateY(-50%)', border: 'none', background: 'none', padding: 6, cursor: 'pointer', color: open ? 'var(--primary)' : 'var(--ink-soft)', display: 'flex' }}>
        <Icon name="clock" size={16} />
      </button>
      {open && (
        <div ref={listRef} role="listbox" aria-label="Horas"
          style={{ position: 'absolute', top: 'calc(100% + 6px)', left: 0, zIndex: 60, background: 'var(--surface)', border: '1px solid var(--line)', borderRadius: 14, boxShadow: '0 16px 40px rgba(0,0,0,.14)', padding: 6, width: '100%', minWidth: 96, maxHeight: 216, overflowY: 'auto' }}>
          {options.map((t) => {
            const sel = t === value;
            return (
              <button key={t} type="button" role="option" aria-selected={sel} data-time={t} onClick={() => pick(t)}
                style={{ display: 'block', width: '100%', font: `${sel ? 700 : 500} 13px var(--ui)`, color: sel ? '#fff' : 'var(--ink)', background: sel ? 'var(--primary)' : 'none', border: 'none', borderRadius: 9, padding: '7px 0', cursor: 'pointer', textAlign: 'center' }}>{t}</button>
            );
          })}
        </div>
      )}
    </div>
  );
}

// ── Campo de palavra-passe com botão mostrar/ocultar ─────────────────
function PasswordInput({ id, value, onChange, placeholder, onEnter, autoComplete = 'current-password', autoFocus }) {
  const [show, setShow] = React.useState(false);
  return (
    <div style={{ position: 'relative' }}>
      <input
        id={id}
        className="pedal-input"
        style={{ paddingRight: 40 }}
        type={show ? 'text' : 'password'}
        autoComplete={autoComplete}
        autoFocus={autoFocus}
        value={value}
        onChange={(e) => onChange(e.target.value)}
        placeholder={placeholder}
        onKeyDown={(e) => { if (e.key === 'Enter' && onEnter) onEnter(); }}
      />
      <button
        type="button"
        onClick={() => setShow((s) => !s)}
        aria-label={show ? 'Ocultar palavra-passe' : 'Mostrar palavra-passe'}
        style={{ position: 'absolute', right: 10, top: 0, height: '100%', display: 'flex', alignItems: 'center', color: 'var(--ink-soft)' }}
      >
        <Icon name={show ? 'eye-off' : 'eye'} size={17} />
      </button>
    </div>
  );
}

Object.assign(window, { Icon, PedalMark, Avatar, TypingDots, QuickReplies, Placeholder, ProgressBar, Pill, DateInputPT, TimeInputPT, PasswordInput });
