// Schedule picker — cadence chips + time picker, with raw-cron escape hatch.
// Emits a cron expression via onChange(cron). Reads + writes via croniter on
// the server (POST /api/strategies/validate-cron) so the preview "next 5
// fires" stays accurate.

window.SchedulePicker = function SchedulePicker({ value, onChange }) {
  const { useState, useEffect, useMemo, useRef } = React;

  // Keep the latest onChange in a ref so the emit effect can depend on `cron`
  // alone. The parent passes a fresh onChange (setField('schedule_cron'))
  // every render; depending on it directly caused an infinite render loop
  // (effect → onChange → parent setState → new onChange → effect → …).
  const onChangeRef = useRef(onChange);
  onChangeRef.current = onChange;

  // Parse incoming cron back into cadence+time, with a fallback to 'advanced'.
  const [mode, setMode] = useState(() => _detectCadence(value).mode);
  const [hour, setHour] = useState(() => _detectCadence(value).hour);
  const [minute, setMinute] = useState(() => _detectCadence(value).minute);
  const [weekday, setWeekday] = useState(() => _detectCadence(value).weekday);  // for Weekly
  const [dayOfMonth, setDayOfMonth] = useState(() => _detectCadence(value).dayOfMonth);  // for Monthly
  const [advancedCron, setAdvancedCron] = useState(value || '0 6 * * 1-5');
  const [preview, setPreview] = useState({ valid: true, next_5_fires: [] });

  const cron = useMemo(() => {
    if (mode === 'advanced') return advancedCron;
    return _toCron(mode, { hour, minute, weekday, dayOfMonth });
  }, [mode, hour, minute, weekday, dayOfMonth, advancedCron]);

  useEffect(() => { onChangeRef.current(cron); }, [cron]);

  useEffect(() => {
    let alive = true;
    window.EQ_API.validateCron(cron).then(r => {
      if (alive) setPreview(r);
    }).catch(() => alive && setPreview({ valid: false, error: 'Could not validate' }));
    return () => { alive = false; };
  }, [cron]);

  return (
    <div style={{
      border: '1px solid var(--ink-200)', borderRadius: 8,
      background: 'var(--ink-50)', padding: 12,
      display: 'flex', flexDirection: 'column', gap: 10,
    }}>
      <Row label="Cadence">
        {['daily', 'weekdays', 'weekly', 'monthly', 'advanced'].map(m => (
          <Chip key={m} selected={mode === m} onClick={() => setMode(m)}>
            {{ daily: 'Daily', weekdays: 'Weekdays', weekly: 'Weekly', monthly: 'Monthly', advanced: 'Advanced (cron)' }[m]}
          </Chip>
        ))}
      </Row>

      {mode !== 'advanced' ? (
        <Row label="Run at">
          <NumInput value={hour} min={0} max={23} onChange={setHour} width={56}/>
          <span style={{ color: 'var(--ink-500)' }}>:</span>
          <NumInput value={minute} min={0} max={59} onChange={setMinute} width={56}/>
          <span style={{ fontSize: 11.5, color: 'var(--ink-500)' }}>PT</span>
          {mode === 'weekly' && (
            <select value={weekday} onChange={e => setWeekday(Number(e.target.value))}
              style={{ marginLeft: 8, padding: '5px 8px', fontSize: 12, borderRadius: 6, border: '1px solid var(--ink-200)', fontFamily: 'inherit' }}>
              {['Sun','Mon','Tue','Wed','Thu','Fri','Sat'].map((d, i) => <option key={i} value={i}>{d}</option>)}
            </select>
          )}
          {mode === 'monthly' && (
            <NumInput value={dayOfMonth} min={1} max={31} onChange={setDayOfMonth} width={56}/>
          )}
        </Row>
      ) : (
        <Row label="Cron">
          <input value={advancedCron} onChange={e => setAdvancedCron(e.target.value)}
            placeholder="0 6 * * 1-5"
            style={{ flex: 1, padding: '6px 10px', fontSize: 12.5, fontFamily: 'var(--font-mono)',
                     border: '1px solid var(--ink-200)', borderRadius: 7, background: 'var(--paper)' }}/>
        </Row>
      )}

      <div style={{ fontFamily: 'var(--font-mono)', fontSize: 11.5, color: preview.valid ? 'var(--ink-500)' : 'var(--pass)' }}>
        {preview.valid
          ? <>Cron: <b style={{ color: 'var(--ink-800)' }}>{cron}</b> · next fire {preview.next_5_fires?.[0] ? new Date(preview.next_5_fires[0]).toLocaleString('en-US', { weekday: 'short', month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit', hour12: true, timeZone: 'America/Vancouver' }) + ' PT' : '—'}</>
          : <>Invalid: {preview.error || 'cron expression'}</>}
      </div>
    </div>
  );
};

function Row({ label, children }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap', gap: 8 }}>
      <span style={{ fontSize: 11.5, color: 'var(--ink-500)', marginRight: 4, minWidth: 60 }}>{label}:</span>
      {children}
    </div>
  );
}

function Chip({ selected, onClick, children }) {
  return (
    <button type="button" onClick={onClick} style={{
      padding: '5px 11px', fontSize: 12, fontWeight: 500,
      background: selected ? 'var(--ink-900)' : 'var(--paper)',
      color: selected ? 'white' : 'var(--ink-700)',
      border: '1px solid ' + (selected ? 'var(--ink-900)' : 'var(--ink-200)'),
      borderRadius: 7, cursor: 'pointer', fontFamily: 'inherit',
    }}>{children}</button>
  );
}

function NumInput({ value, min, max, onChange, width }) {
  return (
    <input type="number" value={value} min={min} max={max}
      onChange={e => onChange(Math.max(min, Math.min(max, Number(e.target.value) || 0)))}
      style={{
        width, padding: '5px 8px', fontSize: 12.5, fontFamily: 'var(--font-mono)',
        border: '1px solid var(--ink-200)', borderRadius: 6, background: 'var(--paper)', textAlign: 'center',
      }}/>
  );
}

// ---- cadence ⇄ cron conversion -----------------------------------------
function _detectCadence(cron) {
  const fallback = { mode: 'weekdays', hour: 6, minute: 0, weekday: 1, dayOfMonth: 1 };
  if (!cron) return fallback;
  const p = cron.trim().split(/\s+/);
  if (p.length !== 5) return { ...fallback, mode: 'advanced' };
  const [mn, hr, dom, mo, dow] = p;
  const minute = Number(mn) || 0;
  const hour = Number(hr) || 0;
  if (mo !== '*' || isNaN(minute) || isNaN(hour)) return { ...fallback, mode: 'advanced' };
  if (dom === '*' && dow === '*') return { ...fallback, mode: 'daily', hour, minute };
  if (dom === '*' && dow === '1-5') return { ...fallback, mode: 'weekdays', hour, minute };
  if (dom === '*' && /^[0-6]$/.test(dow)) return { ...fallback, mode: 'weekly', hour, minute, weekday: Number(dow) };
  if (dow === '*' && /^\d+$/.test(dom)) return { ...fallback, mode: 'monthly', hour, minute, dayOfMonth: Number(dom) };
  return { ...fallback, mode: 'advanced' };
}

function _toCron(mode, { hour, minute, weekday, dayOfMonth }) {
  switch (mode) {
    case 'daily':    return `${minute} ${hour} * * *`;
    case 'weekdays': return `${minute} ${hour} * * 1-5`;
    case 'weekly':   return `${minute} ${hour} * * ${weekday}`;
    case 'monthly':  return `${minute} ${hour} ${dayOfMonth} * *`;
    default:         return `${minute} ${hour} * * *`;
  }
}
