import { useCallback, useMemo, useState } from 'react';

import { tasks } from '@/data/task-repository';
import { useBoard } from '@/data/use-board';
import { toGlideTask, type GlideDecision, type GlideTask, type TaskId } from '@/domain/glide';
import { decisionHaptic } from '@/lib/haptics';

export type EngineStatus = 'loading' | 'active' | 'empty';

export type DecisionEngine = {
  /** High level lifecycle of the planning pass. */
  status: EngineStatus;
  /** The single task currently asking for a decision, if any. */
  task: GlideTask | null;
  /** The next few tasks behind the current one (for stacked card visuals). */
  upcoming: GlideTask[];
  /** Record a decision for the current task. */
  answer: (decision: GlideDecision) => void;
  /** The most recent decision the user made (for celebratory flourishes). */
  lastDecision: GlideDecision | null;
  /** Decisions made in this planning session (the pass). */
  decided: number;
  /** Tasks still to consider in this pass. */
  remaining: number;
};

/**
 * The Resistance Zero decision loop, distilled into one reusable hook — and
 * scoped to a single *pass*. A pass considers every currently-open task exactly
 * once: readying removes it from `open` entirely, while resisting leaves it open
 * (softened) but marks it seen so it won't resurface until the next session.
 * When the pass is exhausted the session rests; re-opening Plan starts a fresh
 * pass where resisted tasks return — exactly Mark Foster's "complete scan".
 */
export function useDecisionEngine(): DecisionEngine {
  const board = useBoard(48);

  // `seen` resets every mount, so each time Plan opens it's a fresh pass.
  const [seenIds, setSeenIds] = useState<Set<TaskId>>(() => new Set());
  const [lastDecision, setLastDecision] = useState<GlideDecision | null>(null);

  const openTasks = useMemo(() => board.open.map(toGlideTask), [board.open]);

  const queue = useMemo(
    () => openTasks.filter((task) => !seenIds.has(task.id)),
    [openTasks, seenIds]
  );

  const task = queue[0] ?? null;
  const upcoming = useMemo(() => queue.slice(1, 4), [queue]);

  const answer = useCallback(
    (decision: GlideDecision) => {
      const current = queue[0];
      if (!current) return;
      decisionHaptic(decision);
      setLastDecision(decision);
      setSeenIds((seen) => new Set(seen).add(current.id));
      tasks.assess(current.id, decision);
    },
    [queue]
  );

  const decided = seenIds.size;
  const remaining = queue.length;
  const status: EngineStatus = task ? 'active' : 'empty';

  return { status, task, upcoming, answer, lastDecision, decided, remaining };
}
