/* Track & Train — utilities & shared components */
const { useState, useEffect, useRef, useMemo, useCallback, createContext, useContext, Fragment } = React;

// ---------- Utilities ----------
const uid = (p='id') => `${p}_${Math.random().toString(36).slice(2,9)}${Date.now().toString(36).slice(-3)}`;

// date helpers — all dates as 'YYYY-MM-DD' local
const pad = (n) => String(n).padStart(2, '0');
const toKey = (d) => `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())}`;
const todayKey = () => toKey(new Date());
const parseKey = (k) => { const [y,m,d] = k.split('-').map(Number); return new Date(y, m-1, d); };

// Build a 6-row (42-cell) month matrix, Monday-first
const monthMatrix = (year, month) => {
  const first = new Date(year, month, 1);
  let startDow = first.getDay(); // 0=Sun
  startDow = (startDow + 6) % 7;  // Mon=0
  const cells = [];
  const start = new Date(year, month, 1 - startDow);
  for (let i = 0; i < 42; i++) {
    const d = new Date(start.getFullYear(), start.getMonth(), start.getDate() + i);
    cells.push(d);
  }
  return cells;
};

// ---------- Feeling scale ----------
const FEELINGS = [
  { v: 1, emoji: '😣', key: 'feel1' },
  { v: 2, emoji: '😕', key: 'feel2' },
  { v: 3, emoji: '😐', key: 'feel3' },
  { v: 4, emoji: '🙂', key: 'feel4' },
  { v: 5, emoji: '🤩', key: 'feel5' },
];
const feelingOf = (v) => FEELINGS.find(f => f.v === v) || null;
const feelLabel = (v) => { const f = feelingOf(v); return f ? t(f.key) : ''; };

// ---------- Type colors ----------
const TYPE_COLORS = ['#ff6b1a','#2f74c0','#1f8a5b','#7a5af0','#d6457e','#d99a16','#128a82','#5a6472'];

// ---------- Storage ----------
const STORAGE_KEY = 'track-train-data-v1';
const loadData = () => {
  try { const raw = localStorage.getItem(STORAGE_KEY); return raw ? JSON.parse(raw) : null; }
  catch (e) { return null; }
};
const saveData = (data) => { try { localStorage.setItem(STORAGE_KEY, JSON.stringify(data)); } catch (e) {} };

// ---------- Seed ----------
const demoSeed = () => {
  const types = [
    { id: 'typ_musc',  name: 'Strength',  color: '#ff6b1a' },
    { id: 'typ_sprint',name: 'Sprint',    color: '#2f74c0' },
    { id: 'typ_lancer',name: 'Throwing',  color: '#1f8a5b' },
    { id: 'typ_endur', name: 'Endurance', color: '#7a5af0' },
    { id: 'typ_mobil', name: 'Mobility',  color: '#d99a16' },
  ];
  const today = new Date();
  const dk = (offset) => { const d = new Date(today.getFullYear(), today.getMonth(), today.getDate() + offset); return toKey(d); };
  const sessions = [
    { id: uid('ses'), date: dk(0),  typeId: 'typ_musc',   feeling: 4, notes: 'Squat 5x5 at 100kg, bench press 4x6. Felt strong.', createdAt: Date.now() },
    { id: uid('ses'), date: dk(0),  typeId: 'typ_mobil',  feeling: 3, notes: 'Hip + shoulder mobility, 20 min.', createdAt: Date.now()+1 },
    { id: uid('ses'), date: dk(-1), typeId: 'typ_sprint', feeling: 5, notes: '6x60m block starts. Explosive, best times of the season.', createdAt: Date.now()+2 },
    { id: uid('ses'), date: dk(-2), typeId: 'typ_lancer',  feeling: 2, notes: 'Javelin technique, arm felt a bit stiff today.', createdAt: Date.now()+3 },
    { id: uid('ses'), date: dk(-4), typeId: 'typ_endur',  feeling: 4, notes: '45 min easy aerobic run.', createdAt: Date.now()+4 },
    { id: uid('ses'), date: dk(-5), typeId: 'typ_musc',   feeling: 3, notes: 'Lower body: lunges, Romanian deadlift.', createdAt: Date.now()+5 },
    { id: uid('ses'), date: dk(-7), typeId: 'typ_sprint', feeling: 4, notes: 'Cadence work, skipping + high knees.', createdAt: Date.now()+6 },
    { id: uid('ses'), date: dk(-9), typeId: 'typ_lancer',  feeling: 5, notes: 'Great throwing session, good rotation.', createdAt: Date.now()+7 },
    { id: uid('ses'), date: dk(-11),typeId: 'typ_endur',  feeling: 3, notes: '1h bike, active recovery.', createdAt: Date.now()+8 },
    { id: uid('ses'), date: dk(-14),typeId: 'typ_musc',   feeling: 4, notes: 'Upper body + core.', createdAt: Date.now()+9 },
  ];
  return { types, sessions };
};
const blankData = () => ({
  types: [
    { id: 'typ_musc',  name: 'Strength', color: '#ff6b1a' },
    { id: 'typ_cardio',name: 'Cardio',   color: '#2f74c0' },
    { id: 'typ_tech',  name: 'Technique',color: '#1f8a5b' },
  ],
  sessions: [],
});

// ---------- Icons (inline SVG, Track & Throw stroke style) ----------
const Icon = {
  calendar:(p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}><rect x="3.5" y="5" width="17" height="16" rx="2.5"/><path d="M3.5 9.5h17M8 3v4M16 3v4"/></svg>,
  layers:  (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M12 3l9 5-9 5-9-5 9-5z"/><path d="M3 13l9 5 9-5"/></svg>,
  tag:     (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M3.5 11.5V5a1.5 1.5 0 0 1 1.5-1.5h6.5a2 2 0 0 1 1.4.6l7 7a2 2 0 0 1 0 2.8l-6.6 6.6a2 2 0 0 1-2.8 0l-7-7a2 2 0 0 1-.6-1.4z"/><circle cx="8" cy="8" r="1.4" fill="currentColor" stroke="none"/></svg>,
  settings:(p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.7 1.7 0 0 0 .35 1.85l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.7 1.7 0 0 0-1.85-.35 1.7 1.7 0 0 0-1 1.55V21a2 2 0 0 1-4 0v-.1a1.7 1.7 0 0 0-1.1-1.55 1.7 1.7 0 0 0-1.85.35l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.7 1.7 0 0 0 .35-1.85 1.7 1.7 0 0 0-1.55-1H3a2 2 0 0 1 0-4h.1a1.7 1.7 0 0 0 1.55-1.1 1.7 1.7 0 0 0-.35-1.85l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.7 1.7 0 0 0 1.85.35h0a1.7 1.7 0 0 0 1-1.55V3a2 2 0 0 1 4 0v.1a1.7 1.7 0 0 0 1 1.55 1.7 1.7 0 0 0 1.85-.35l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.7 1.7 0 0 0-.35 1.85v0a1.7 1.7 0 0 0 1.55 1H21a2 2 0 0 1 0 4h-.1a1.7 1.7 0 0 0-1.55 1z"/></svg>,
  plus:    (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M12 5v14M5 12h14"/></svg>,
  plusSm:  (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M12 5v14M5 12h14"/></svg>,
  back:    (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.9" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M15 6l-6 6 6 6"/></svg>,
  trash:   (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M4 7h16M9 7V5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2"/><path d="M6 7l1.2 12a2 2 0 0 0 2 1.8h5.6a2 2 0 0 0 2-1.8L18 7"/></svg>,
  close:   (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.9" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M6 6l12 12M18 6l-12 12"/></svg>,
  chev:    (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M9 6l6 6-6 6"/></svg>,
  chevL:   (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.9" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M15 6l-6 6 6 6"/></svg>,
  chevR:   (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.9" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M9 6l6 6-6 6"/></svg>,
  edit:    (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M4 20h4l10-10-4-4L4 16v4z"/><path d="M14 6l4 4"/></svg>,
  check:   (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M5 12l5 5L20 7"/></svg>,
  dots:    (p) => <svg viewBox="0 0 24 24" fill="currentColor" {...p}><circle cx="6" cy="12" r="1.5"/><circle cx="12" cy="12" r="1.5"/><circle cx="18" cy="12" r="1.5"/></svg>,
  download:(p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M12 4v12M6 12l6 6 6-6M5 20h14"/></svg>,
  upload:  (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M12 20V8M6 12l6-6 6 6M5 4h14"/></svg>,
  flame:   (p) => <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" {...p}><path d="M12 3c1.5 3 4.5 4.5 4.5 8.5A4.5 4.5 0 0 1 12 16a4.5 4.5 0 0 1-4.5-4.5C7.5 9 9 8 9 6c1.5 1 1.5 2.5 1.5 2.5S11 5.5 12 3z"/><path d="M12 21a5 5 0 0 0 5-5c0-1-.2-1.8-.5-2.5A6 6 0 0 1 12 16a6 6 0 0 1-4.5-2.5A6 6 0 0 0 7 16a5 5 0 0 0 5 5z"/></svg>,
};

// ---------- Toast ----------
const ToastContext = createContext(null);
const useToast = () => useContext(ToastContext);
const ToastProvider = ({ children }) => {
  const [msg, setMsg] = useState(null);
  const tRef = useRef(null);
  const show = useCallback((text) => {
    setMsg(text);
    clearTimeout(tRef.current);
    tRef.current = setTimeout(() => setMsg(null), 1800);
  }, []);
  return (
    <ToastContext.Provider value={show}>
      {children}
      <div className={'toast ' + (msg ? 'show' : '')}>{msg}</div>
    </ToastContext.Provider>
  );
};

// ---------- Sheet (bottom modal) ----------
const Sheet = ({ open, onClose, title, children, action, maxWidth }) => {
  useEffect(() => {
    if (!open) return;
    const h = (e) => { if (e.key === 'Escape') onClose(); };
    window.addEventListener('keydown', h);
    return () => window.removeEventListener('keydown', h);
  }, [open, onClose]);
  return (
    <div style={{ display: 'contents' }}>
      <div className={'scrim ' + (open ? 'open' : '')} onClick={onClose}></div>
      <div className={'sheet ' + (open ? 'open' : '')} style={maxWidth ? { maxWidth } : null}>
        <div className="sheet-grabber"></div>
        <div className="sheet-head">
          <h2>{title}</h2>
          {action}
          <button className="icon-btn" onClick={onClose} aria-label="Fermer"><Icon.close/></button>
        </div>
        <div className="sheet-body">{children}</div>
      </div>
    </div>
  );
};

// ---------- Confirm dialog ----------
const useConfirm = () => {
  const [state, setState] = useState(null);
  const ask = useCallback((opts) => new Promise(res => setState({ ...opts, res })), []);
  const close = (v) => { if (state) { state.res(v); setState(null); } };
  const ui = state && (
    <div style={{ display: 'contents' }}>
      <div className="scrim open" onClick={() => close(false)}></div>
      <div className="sheet open" style={{maxWidth: 360}}>
        <div className="sheet-grabber"></div>
        <div className="sheet-body">
          <h3 style={{margin:'4px 0 6px', fontSize:17}}>{state.title}</h3>
          {state.message && <p className="muted" style={{margin:'0 0 16px', fontSize:13.5}}>{state.message}</p>}
          <div className="flex gap-8">
            <button className="btn secondary flex-1" onClick={() => close(false)}>{state.cancelLabel || 'Annuler'}</button>
            <button className={'btn flex-1 ' + (state.danger ? 'danger' : '')} onClick={() => close(true)}>{state.confirmLabel || 'OK'}</button>
          </div>
        </div>
      </div>
    </div>
  );
  return { ask, ui };
};

// Expose globals
Object.assign(window, {
  React, useState, useEffect, useRef, useMemo, useCallback, Fragment,
  uid, pad, toKey, todayKey, parseKey,
  monthMatrix,
  FEELINGS, feelingOf, feelLabel, TYPE_COLORS,
  loadData, saveData, demoSeed, blankData,
  Icon, ToastProvider, useToast, Sheet, useConfirm,
});
