/* global React, Icon, IconBtn, db */
const { useState, useEffect, useRef, useMemo, useCallback } = React;

// ============================================================
// Pomodoro Timer
// ------------------------------------------------------------
// A focus-session timer that cycles:
//    focus → short break → focus → short break → … → long break
// after every Nth pomodoro.
//
// State persists in db.kv under three records so a refresh during
// a session doesn't lose time:
//   pomodoroState     — current phase + status + end timestamp
//   pomodoroSettings  — durations & preferences
//   pomodoroHistory   — last 200 completed phases (for today's stats)
//
// We store an ABSOLUTE `phaseEndsAt` timestamp while running, not a
// remaining duration. That way reloading the tab while the timer is
// going just keeps counting down from `phaseEndsAt - now`, and if it
// already passed we advance the phase on resume.
// ============================================================

const POMO_PHASES = {
  focus: { label: 'Focus',       short: 'Focus',  icon: 'bolt',         tone: 'focus' },
  short: { label: 'Short break', short: 'Break',  icon: 'coffee',       tone: 'short' },
  long:  { label: 'Long break',  short: 'Long',   icon: 'self_improvement', tone: 'long'  },
};

const POMO_DEFAULT_SETTINGS = {
  focusMin: 25,
  shortMin: 5,
  longMin: 15,
  cyclesPerLong: 4,    // every Nth focus phase triggers a long break
  sound: true,
  autoStart: false,    // auto-roll into the next phase
};

const POMO_DEFAULT_STATE = {
  phase: 'focus',
  status: 'idle',      // 'idle' | 'running' | 'paused'
  phaseEndsAt: null,   // ms timestamp
  remainingMs: null,   // populated when paused
  cycleCount: 0,       // focus phases completed in current set (resets after long break)
  task: '',
};

// ------------------------------------------------------------
// Audio chime — generated with Web Audio so no external assets.
// Different tones per phase so the user can tell what just ended
// without looking.
// ------------------------------------------------------------
let pomoAudioCtx = null;
function playPomoChime(tone = 'focus') {
  try {
    if (!pomoAudioCtx) pomoAudioCtx = new (window.AudioContext || window.webkitAudioContext)();
    const ctx = pomoAudioCtx;
    const now = ctx.currentTime;
    // Pattern: a small two-note chime per tone
    const patterns = {
      focus: [[880, 0],   [660, 0.16]],   // descending — focus complete, rest now
      short: [[660, 0],   [880, 0.16]],   // ascending — back to work
      long:  [[523, 0],   [659, 0.16], [784, 0.32]], // C-E-G — earned rest
    };
    for (const [freq, when] of (patterns[tone] || patterns.focus)) {
      const osc = ctx.createOscillator();
      const gain = ctx.createGain();
      osc.type = 'sine';
      osc.frequency.setValueAtTime(freq, now + when);
      gain.gain.setValueAtTime(0.0001, now + when);
      gain.gain.exponentialRampToValueAtTime(0.18, now + when + 0.02);
      gain.gain.exponentialRampToValueAtTime(0.0001, now + when + 0.45);
      osc.connect(gain).connect(ctx.destination);
      osc.start(now + when);
      osc.stop(now + when + 0.5);
    }
  } catch (e) { /* swallow — sound is optional */ }
}

// ------------------------------------------------------------
// Time formatting
// ------------------------------------------------------------
function fmtPomoTime(ms) {
  const total = Math.max(0, Math.round(ms / 1000));
  const m = Math.floor(total / 60);
  const s = total % 60;
  return `${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`;
}
function fmtPomoMinutesLabel(min) {
  const h = Math.floor(min / 60);
  const m = min % 60;
  if (h <= 0) return `${m}m`;
  if (m === 0) return `${h}h`;
  return `${h}h ${m}m`;
}

// ------------------------------------------------------------
// Hook: live-load state/settings from db.kv with subscribe
// ------------------------------------------------------------
function usePomoStore() {
  const [state, setState] = useState(POMO_DEFAULT_STATE);
  const [settings, setSettings] = useState(POMO_DEFAULT_SETTINGS);
  const [history, setHistory] = useState([]);
  const [loaded, setLoaded] = useState(false);

  useEffect(() => {
    let mounted = true;
    const load = async () => {
      const [s, set, h] = await Promise.all([
        db.kv.get('pomodoroState'),
        db.kv.get('pomodoroSettings'),
        db.kv.get('pomodoroHistory'),
      ]);
      if (!mounted) return;
      setState({ ...POMO_DEFAULT_STATE, ...(s?.v || {}) });
      setSettings({ ...POMO_DEFAULT_SETTINGS, ...(set?.v || {}) });
      setHistory(Array.isArray(h?.v) ? h.v : []);
      setLoaded(true);
    };
    load();
    const unsub = db.subscribe(({ store, value }) => {
      if (store !== 'kv') return;
      const k = value?.k;
      if (!k) return;
      if (k === 'pomodoroState')    db.kv.get('pomodoroState').then(r => setState({ ...POMO_DEFAULT_STATE, ...(r?.v || {}) }));
      if (k === 'pomodoroSettings') db.kv.get('pomodoroSettings').then(r => setSettings({ ...POMO_DEFAULT_SETTINGS, ...(r?.v || {}) }));
      if (k === 'pomodoroHistory')  db.kv.get('pomodoroHistory').then(r => setHistory(Array.isArray(r?.v) ? r.v : []));
    });
    return () => { mounted = false; unsub(); };
  }, []);

  const saveState    = useCallback((v) => db.kv.put({ k: 'pomodoroState',    v }), []);
  const saveSettings = useCallback((v) => db.kv.put({ k: 'pomodoroSettings', v }), []);
  const saveHistory  = useCallback((v) => db.kv.put({ k: 'pomodoroHistory',  v }), []);

  return { state, settings, history, loaded, saveState, saveSettings, saveHistory };
}

// ------------------------------------------------------------
// Phase math — given the current cycle count and settings, what
// phase comes next?
// ------------------------------------------------------------
function nextPhase(currentPhase, cycleCount, settings) {
  if (currentPhase === 'focus') {
    // Just finished a focus phase; cycleCount has been bumped.
    return cycleCount > 0 && cycleCount % settings.cyclesPerLong === 0 ? 'long' : 'short';
  }
  // Just finished any break → back to focus.
  return 'focus';
}
function durationFor(phase, settings) {
  return (phase === 'focus' ? settings.focusMin
        : phase === 'short' ? settings.shortMin
        :                     settings.longMin) * 60 * 1000;
}

// ============================================================
// PomodoroTool — main component
// ============================================================
function PomodoroTool() {
  const { state, settings, history, loaded, saveState, saveSettings, saveHistory } = usePomoStore();
  const [now, setNow] = useState(Date.now());
  const [showSettings, setShowSettings] = useState(false);
  const tickRef = useRef(null);
  const lastTickPhaseEnd = useRef(null);

  // 1Hz tick while running — enough for a clean MM:SS display.
  useEffect(() => {
    if (state.status !== 'running') {
      if (tickRef.current) { clearInterval(tickRef.current); tickRef.current = null; }
      return;
    }
    setNow(Date.now());
    tickRef.current = setInterval(() => setNow(Date.now()), 1000);
    return () => { if (tickRef.current) { clearInterval(tickRef.current); tickRef.current = null; } };
  }, [state.status]);

  // ---------- Compute remaining time ----------
  const phaseDuration = durationFor(state.phase, settings);
  const remaining = state.status === 'running'
    ? Math.max(0, (state.phaseEndsAt || 0) - now)
    : state.status === 'paused'
      ? (state.remainingMs ?? phaseDuration)
      : phaseDuration;
  const elapsed = phaseDuration - remaining;
  const progress = phaseDuration > 0 ? Math.min(1, elapsed / phaseDuration) : 0;

  // ---------- Phase-end side effects ----------
  // When `running` and remaining reaches 0, complete the phase and roll into the next.
  // We guard with a ref so we don't double-fire across the 1s tick.
  useEffect(() => {
    if (state.status !== 'running' || !state.phaseEndsAt) return;
    if (remaining > 0) return;
    if (lastTickPhaseEnd.current === state.phaseEndsAt) return;
    lastTickPhaseEnd.current = state.phaseEndsAt;
    completePhase();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [remaining, state.status, state.phaseEndsAt]);

  // ---------- Document title — keep the timer visible in the tab ----------
  useEffect(() => {
    if (state.status === 'running') {
      const orig = document.title;
      document.title = `${fmtPomoTime(remaining)} · ${POMO_PHASES[state.phase].short} — Pomodoro`;
      return () => { document.title = orig; };
    }
  }, [state.status, state.phase, remaining]);

  // ---------- Actions ----------
  const start = () => {
    // Ensure AudioContext is created in response to user gesture
    if (settings.sound && !pomoAudioCtx) {
      try { pomoAudioCtx = new (window.AudioContext || window.webkitAudioContext)(); } catch (e) {}
    }
    const duration = state.status === 'paused' && state.remainingMs != null
      ? state.remainingMs
      : phaseDuration;
    saveState({
      ...state,
      status: 'running',
      phaseEndsAt: Date.now() + duration,
      remainingMs: null,
    });
  };

  const pause = () => {
    saveState({
      ...state,
      status: 'paused',
      phaseEndsAt: null,
      remainingMs: remaining,
    });
  };

  const reset = () => {
    saveState({
      ...state,
      status: 'idle',
      phaseEndsAt: null,
      remainingMs: null,
    });
  };

  const setTask = (t) => {
    saveState({ ...state, task: t });
  };

  const completePhase = async () => {
    // 1. record history
    const completedAt = Date.now();
    const entry = {
      ts: completedAt,
      phase: state.phase,
      durationMs: phaseDuration,
      task: state.task || '',
    };
    const nextHistory = [entry, ...history].slice(0, 200);
    saveHistory(nextHistory);

    // 2. chime
    if (settings.sound) playPomoChime(POMO_PHASES[state.phase].tone);

    // 3. compute next phase
    let nextCycle = state.cycleCount;
    if (state.phase === 'focus') nextCycle += 1;
    // If we just finished a long break, the cycle counter rolls back to 0
    if (state.phase === 'long')  nextCycle = 0;

    const np = nextPhase(state.phase, nextCycle, settings);

    // 4. update state — either auto-start or idle waiting for user
    const nextState = {
      ...state,
      phase: np,
      cycleCount: nextCycle,
      status: settings.autoStart ? 'running' : 'idle',
      phaseEndsAt: settings.autoStart ? Date.now() + durationFor(np, settings) : null,
      remainingMs: null,
    };
    saveState(nextState);

    // 5. browser notification if granted
    if ('Notification' in window && Notification.permission === 'granted') {
      try {
        new Notification(`${POMO_PHASES[state.phase].label} complete`, {
          body: settings.autoStart
            ? `Next: ${POMO_PHASES[np].label}`
            : `Tap to start ${POMO_PHASES[np].label}`,
          silent: true,
        });
      } catch (e) {}
    }
  };

  const skipPhase = () => {
    // Treat "skip" as completing without recording history — feels closer to
    // user intent than a counted skip, and avoids gaming the streak.
    let nextCycle = state.cycleCount;
    if (state.phase === 'focus') nextCycle += 1;
    if (state.phase === 'long')  nextCycle = 0;
    const np = nextPhase(state.phase, nextCycle, settings);
    saveState({
      ...state,
      phase: np,
      cycleCount: nextCycle,
      status: 'idle',
      phaseEndsAt: null,
      remainingMs: null,
    });
  };

  const switchPhase = (p) => {
    // Manually switch phase from the segmented control.
    saveState({
      ...state,
      phase: p,
      status: 'idle',
      phaseEndsAt: null,
      remainingMs: null,
    });
  };

  // ---------- Today's stats ----------
  const startOfToday = useMemo(() => {
    const d = new Date(); d.setHours(0,0,0,0); return d.getTime();
  }, [now]);
  const todayFocus = history.filter(h => h.phase === 'focus' && h.ts >= startOfToday);
  const todayFocusMin = Math.round(todayFocus.reduce((a, h) => a + h.durationMs, 0) / 60000);

  if (!loaded) return <div className="pomo-tool pomo-loading" />;

  const phase = POMO_PHASES[state.phase];

  return (
    <div className={`pomo-tool pomo-phase-${state.phase}`}>
      {/* HEADER — phase segmented control + settings */}
      <header className="pomo-header">
        <div className="pomo-phase-tabs">
          {Object.entries(POMO_PHASES).map(([k, p]) => (
            <button
              key={k}
              className={`pomo-phase-tab ${state.phase === k ? 'is-active' : ''}`}
              onClick={() => switchPhase(k)}
            >
              <Icon name={p.icon} />
              <span>{p.label}</span>
            </button>
          ))}
        </div>
        <button
          className={`lh-btn ghost ${showSettings ? 'is-active' : ''}`}
          onClick={() => setShowSettings(s => !s)}
          title="Pomodoro settings"
        >
          <Icon name="tune" />
          Settings
        </button>
      </header>

      {/* SETTINGS DRAWER */}
      {showSettings && (
        <PomodoroSettings settings={settings} onSave={saveSettings} onClose={() => setShowSettings(false)} />
      )}

      {/* TIMER STAGE */}
      <section className="pomo-stage">
        <PomoRing
          progress={progress}
          phase={state.phase}
          remaining={remaining}
          phaseDuration={phaseDuration}
        />

        <div className="pomo-task-wrap">
          <input
            className="pomo-task"
            type="text"
            placeholder={state.phase === 'focus' ? 'What are you focusing on?' : 'Take a real break — step away from the screen.'}
            value={state.task}
            onChange={(e) => setTask(e.target.value)}
            disabled={state.phase !== 'focus'}
            maxLength={120}
          />
        </div>

        {/* Cycle dots — show position in the cyclesPerLong sequence */}
        <CycleDots
          completed={state.cycleCount % settings.cyclesPerLong}
          inFocus={state.phase === 'focus' && state.status !== 'idle'}
          total={settings.cyclesPerLong}
        />

        {/* CONTROLS */}
        <div className="pomo-controls">
          {state.status === 'running' ? (
            <button className="pomo-btn pomo-btn-primary" onClick={pause}>
              <Icon name="pause" />Pause
            </button>
          ) : (
            <button className="pomo-btn pomo-btn-primary" onClick={start}>
              <Icon name="play_arrow" />{state.status === 'paused' ? 'Resume' : 'Start'}
            </button>
          )}
          {state.status !== 'idle' && (
            <button className="pomo-btn pomo-btn-ghost" onClick={reset} title="Reset to full duration">
              <Icon name="refresh" />Reset
            </button>
          )}
          <button className="pomo-btn pomo-btn-ghost" onClick={skipPhase} title="Skip to next phase">
            <Icon name="skip_next" />Skip
          </button>
        </div>
      </section>

      {/* TODAY STATS */}
      <section className="pomo-stats">
        <div className="pomo-stat">
          <div className="pomo-stat-value">{todayFocus.length}</div>
          <div className="pomo-stat-label">Pomodoros today</div>
        </div>
        <div className="pomo-stat">
          <div className="pomo-stat-value">{fmtPomoMinutesLabel(todayFocusMin)}</div>
          <div className="pomo-stat-label">Focus time today</div>
        </div>
        <div className="pomo-stat">
          <div className="pomo-stat-value">{state.cycleCount % settings.cyclesPerLong} / {settings.cyclesPerLong}</div>
          <div className="pomo-stat-label">Until long break</div>
        </div>
      </section>

      {/* RECENT SESSIONS */}
      {todayFocus.length > 0 && (
        <section className="pomo-history">
          <h3>Today's sessions</h3>
          <ul>
            {todayFocus.slice(0, 8).map((h, i) => (
              <li key={i}>
                <span className="pomo-history-time">
                  {new Date(h.ts).toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' })}
                </span>
                <span className="pomo-history-dur">{Math.round(h.durationMs / 60000)}m</span>
                <span className="pomo-history-task">{h.task || <em className="pomo-history-untitled">(no task name)</em>}</span>
              </li>
            ))}
          </ul>
        </section>
      )}
    </div>
  );
}

// ============================================================
// PomoRing — circular progress ring + big timer in the center
// ============================================================
function PomoRing({ progress, phase, remaining, phaseDuration }) {
  // SVG ring math: r = 140, c = 2πr
  const r = 140;
  const c = 2 * Math.PI * r;
  const dashOffset = c * (1 - progress);

  return (
    <div className="pomo-ring-wrap">
      <svg className="pomo-ring" viewBox="0 0 320 320" width="320" height="320">
        <circle cx="160" cy="160" r={r} className="pomo-ring-track" />
        <circle
          cx="160" cy="160" r={r}
          className="pomo-ring-fill"
          strokeDasharray={c}
          strokeDashoffset={dashOffset}
          transform="rotate(-90 160 160)"
        />
      </svg>
      <div className="pomo-ring-center">
        <div className="pomo-ring-phase">
          <Icon name={POMO_PHASES[phase].icon} />
          <span>{POMO_PHASES[phase].label}</span>
        </div>
        <div className="pomo-ring-time">{fmtPomoTime(remaining)}</div>
        <div className="pomo-ring-of">of {Math.round(phaseDuration / 60000)} min</div>
      </div>
    </div>
  );
}

// ============================================================
// CycleDots — N dots showing how many pomodoros until the long break
// ============================================================
function CycleDots({ completed, inFocus, total }) {
  return (
    <div className="pomo-cycle-dots" title={`${completed} of ${total} pomodoros toward long break`}>
      {Array.from({ length: total }, (_, i) => {
        const isDone = i < completed;
        const isCurrent = i === completed && inFocus;
        return (
          <span
            key={i}
            className={`pomo-cycle-dot ${isDone ? 'is-done' : ''} ${isCurrent ? 'is-current' : ''}`}
          />
        );
      })}
    </div>
  );
}

// ============================================================
// PomodoroSettings — inline drawer
// ============================================================
function PomodoroSettings({ settings, onSave, onClose }) {
  const update = (patch) => onSave({ ...settings, ...patch });

  const requestNotifications = async () => {
    if (!('Notification' in window)) return;
    if (Notification.permission === 'granted') return;
    try { await Notification.requestPermission(); } catch (e) {}
  };

  return (
    <div className="pomo-settings">
      <div className="pomo-settings-grid">
        <DurationRow
          label="Focus" icon="bolt"
          value={settings.focusMin} min={5} max={120} step={5}
          onChange={(v) => update({ focusMin: v })}
        />
        <DurationRow
          label="Short break" icon="coffee"
          value={settings.shortMin} min={1} max={30} step={1}
          onChange={(v) => update({ shortMin: v })}
        />
        <DurationRow
          label="Long break" icon="self_improvement"
          value={settings.longMin} min={5} max={60} step={5}
          onChange={(v) => update({ longMin: v })}
        />
        <DurationRow
          label="Long break every" icon="repeat"
          value={settings.cyclesPerLong} min={2} max={8} step={1} unit="pomodoros"
          onChange={(v) => update({ cyclesPerLong: v })}
        />
      </div>

      <div className="pomo-settings-toggles">
        <label className="pomo-settings-toggle">
          <input
            type="checkbox"
            checked={settings.sound}
            onChange={(e) => update({ sound: e.target.checked })}
          />
          <span className="pomo-toggle-track"><span className="pomo-toggle-thumb" /></span>
          <div>
            <div className="pomo-toggle-label">Chime when a phase ends</div>
            <div className="pomo-toggle-sub">A gentle two-note signal — different tones for focus vs break.</div>
          </div>
        </label>
        <label className="pomo-settings-toggle">
          <input
            type="checkbox"
            checked={settings.autoStart}
            onChange={(e) => update({ autoStart: e.target.checked })}
          />
          <span className="pomo-toggle-track"><span className="pomo-toggle-thumb" /></span>
          <div>
            <div className="pomo-toggle-label">Auto-start the next phase</div>
            <div className="pomo-toggle-sub">Rolls focus → break → focus without waiting for you to press play.</div>
          </div>
        </label>
        {'Notification' in window && Notification.permission !== 'granted' && (
          <button className="pomo-permission-btn" onClick={requestNotifications}>
            <Icon name="notifications_active" />
            Allow browser notifications
          </button>
        )}
      </div>

      <div className="pomo-settings-foot">
        <button className="lh-btn ghost" onClick={onClose}>
          <Icon name="close" />Close
        </button>
      </div>
    </div>
  );
}

function DurationRow({ label, icon, value, min, max, step, unit = 'min', onChange }) {
  return (
    <div className="pomo-duration-row">
      <div className="pomo-duration-head">
        <Icon name={icon} />
        <span className="pomo-duration-label">{label}</span>
        <span className="pomo-duration-value">{value} <em>{unit}</em></span>
      </div>
      <input
        type="range"
        className="pomo-duration-slider"
        min={min} max={max} step={step}
        value={value}
        onChange={(e) => onChange(Number(e.target.value))}
      />
    </div>
  );
}

window.PomodoroTool = PomodoroTool;
