// Shared state, storage, helpers, constants.

const DEFAULT_STATE = {
  mission: "show up. ship videos. outwork everyone.",
  habits: [
    { id: 'h1', name: 'no stimulation in bed', frequency: 'daily' },
    { id: 'h2', name: 'work from library', frequency: 'daily' },
    { id: 'h3', name: 'walk', frequency: 'rest' },
  ],
  habitLog: {},
  tags: [
    { id: 't1', name: 'main channel', color: '#7FD4A3', ships: true },
  ],
  inputs: [],
  weeklyGoal: 5,
  sessions: [],
  activeSession: null,
};

const STORAGE_KEY = 'dashboard-v6';

const todayStr = (d = new Date()) =>
  `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;

const getWeekKey = (date = new Date()) => {
  const d = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
  const dayNum = d.getUTCDay() || 7;
  d.setUTCDate(d.getUTCDate() + 4 - dayNum);
  const yearStart = new Date(Date.UTC(d.getUTCFullYear(), 0, 1));
  const weekNum = Math.ceil((((d - yearStart) / 86400000) + 1) / 7);
  return `${d.getUTCFullYear()}-W${String(weekNum).padStart(2, '0')}`;
};

const formatDuration = (sec) => {
  const h = Math.floor(sec / 3600);
  const m = Math.floor((sec % 3600) / 60);
  if (h > 0) return `${h}h ${m}m`;
  return `${m}m`;
};

const pad2 = (n) => String(n).padStart(2, '0');

const TAG_PALETTE = ['#7FD4A3', '#6BA6E8', '#E89B6B', '#C77FD4', '#D4C76B', '#6BD4C9', '#E86B8A'];

const loadState = () => {
  try {
    const raw = localStorage.getItem(STORAGE_KEY);
    if (!raw) {
      // Migrate from v5 if present
      const v5 = localStorage.getItem('dashboard-v5');
      if (v5) return { ...DEFAULT_STATE, ...JSON.parse(v5) };
      return DEFAULT_STATE;
    }
    return { ...DEFAULT_STATE, ...JSON.parse(raw) };
  } catch (e) {
    return DEFAULT_STATE;
  }
};
const saveState = (state) => {
  try { localStorage.setItem(STORAGE_KEY, JSON.stringify(state)); } catch (e) {}
};

// Count-up hook: animates a number from its previous value to the new one.
const { useState, useEffect, useRef, useMemo, useCallback, useLayoutEffect } = React;

function useCountUp(target, { duration = 700, decimals = 0 } = {}) {
  const [display, setDisplay] = useState(target);
  // Track the live displayed value (updated every frame) so interrupted
  // animations resume from where the number visually is, not from the last
  // settled target. Prevents stuck / backwards-jumping values on rapid updates.
  const displayRef = useRef(target);
  const rafRef = useRef(null);

  useEffect(() => {
    cancelAnimationFrame(rafRef.current);
    const from = displayRef.current;
    const to = target;
    if (from === to) {
      displayRef.current = to;
      setDisplay(to);
      return;
    }
    const startTime = performance.now();
    const tick = (now) => {
      const t = Math.min(1, (now - startTime) / duration);
      const eased = 1 - Math.pow(1 - t, 3);
      const v = from + (to - from) * eased;
      displayRef.current = v;
      setDisplay(v);
      if (t < 1) rafRef.current = requestAnimationFrame(tick);
      else { displayRef.current = to; setDisplay(to); }
    };
    rafRef.current = requestAnimationFrame(tick);
    return () => cancelAnimationFrame(rafRef.current);
  }, [target, duration]);

  return decimals === 0 ? Math.round(display) : Number(display.toFixed(decimals));
}

// Expose helpers globally
Object.assign(window, {
  DEFAULT_STATE, STORAGE_KEY, TAG_PALETTE,
  todayStr, getWeekKey, formatDuration, pad2,
  loadState, saveState, useCountUp,
});
