/**
 * Fitbit Device App — Hevy Live Workout Companion (Sense 2 / rhea)
 *
 * Entry point. Sets up UI, messaging, sensors, timers,
 * and the live workout FSM.
 */

import { me as device } from 'device';
import { peerSocket } from 'messaging';
import { vibration } from 'haptics';
import { display } from 'display';
import { document } from 'document';

import {
  createInitialState,
  reduce,
  buildHevyPayload,
  type LiveWorkoutState,
  type WorkoutAction,
} from './state-model';

// ─── Global State ────────────────────────────────────────────────────

let state: LiveWorkoutState = createInitialState();
let restTimerInterval: ReturnType<typeof setInterval> | null = null;

// ─── Dispatch ────────────────────────────────────────────────────────

function dispatch(action: WorkoutAction): void {
  const prevState = state.state;
  state = reduce(state, action);

  // Log transitions
  if (state.state !== prevState) {
    console.log(`[app] FSM: ${prevState} → ${state.state}`);
  }

  // Side effects
  handleSideEffects(action);

  // Update UI
  render();
}

// ─── Side Effects ────────────────────────────────────────────────────

function handleSideEffects(action: WorkoutAction): void {
  switch (action.type) {
    case 'LOAD_PLAN':
      sendToCompanion({ type: 'REQUEST_PLAN' });
      break;

    case 'LOG_SET': {
      if (!state.plan) break;
      const ex = state.plan.exercises[state.currentExerciseIndex];
      const set = ex.sets[state.currentSetIndex];
      sendToCompanion({
        type: 'SET_COMPLETE',
        eventId: `set-${Date.now()}-${state.currentExerciseIndex}-${state.currentSetIndex}`,
        exerciseIndex: state.currentExerciseIndex,
        setIndex: state.currentSetIndex,
        exerciseTemplateId: ex.hevyTemplateId,
        weightKg: action.weightKg,
        reps: action.reps,
        rir: action.rir,
      });
      // Start rest timer
      startRestTimer();
      break;
    }

    case 'START_REST':
      startRestTimer();
      break;


    case 'FINISH_WORKOUT': {
      sendToCompanion({
        type: 'FINISH_WORKOUT',
        startedAt: state.workoutStartedAt,
        endedAt: state.workoutEndedAt,
      });
      dispatch({ type: 'SYNC_START' });
      break;
    }

    case 'SKIP_REST':
      stopRestTimer();
      break;

    case 'RESET':
      stopRestTimer();
      break;
  }

  // Vibration for state transitions
  if (action.type === 'TICK_REST' && state.resting.remainingSec <= 3 && state.resting.remainingSec > 0) {
    vibration.start('ping');
  }
  if (state.state === 'RESTING' && action.type === 'LOG_SET') {
    vibration.start('nudge');
  }
  if (state.state === 'COMPLETE') {
    vibration.start('confirmation');
  }
}

// ─── Rest Timer ──────────────────────────────────────────────────────

function startRestTimer(): void {
  stopRestTimer();
  restTimerInterval = setInterval(() => {
    dispatch({ type: 'TICK_REST' });
    if (state.resting.remainingSec <= 0) {
      stopRestTimer();
    }
  }, 1000);
}

function stopRestTimer(): void {
  if (restTimerInterval !== null) {
    clearInterval(restTimerInterval);
    restTimerInterval = null;
  }
}

// ─── Messaging: Watch → Companion ────────────────────────────────────

function sendToCompanion(data: Record<string, unknown>): void {
  if (peerSocket.readyState === peerSocket.OPEN) {
    peerSocket.send(data);
  } else {
    // Queue for later: push to pendingEvents in state
    console.log(`[app] Companion not connected, event queued`);
    dispatch({ type: 'SET_OFFLINE', isOffline: true });
  }
}

// ─── Messaging: Companion → Watch ────────────────────────────────────

peerSocket.addEventListener('message', (evt: any) => {
  const msg: { type: string; [key: string]: unknown } = evt.data;

  switch (msg.type) {
    case 'PLAN_LOADED':
      if (msg.plan) dispatch({ type: 'PLAN_LOADED', plan: msg.plan as NonNullable<LiveWorkoutState['plan']> });
      break;

    case 'PLAN_LOAD_ERROR':
      dispatch({ type: 'PLAN_LOAD_ERROR', error: msg.error as string });
      break;

    case 'SET_ACK':
      if (msg.serverConfirmed) {
        dispatch({ type: 'EVENT_ACKED', eventId: msg.eventId as string });
      }
      break;

    case 'SYNC_SUCCESS':
      dispatch({ type: 'SYNC_SUCCESS', hevyWorkoutId: msg.hevyWorkoutId as string });
      break;

    case 'SYNC_ERROR':
      dispatch({ type: 'SYNC_ERROR', error: msg.error as string });
      break;

    case 'HEARTBEAT_ACK':
      dispatch({ type: 'SET_OFFLINE', isOffline: !msg.backendReachable });
      break;

    default:
      console.log(`[app] Unknown companion message: ${msg.type}`);
  }
});

peerSocket.addEventListener('open', () => {
  console.log('[app] Companion connected');
  dispatch({ type: 'SET_OFFLINE', isOffline: false });
});

peerSocket.addEventListener('close', () => {
  console.log('[app] Companion disconnected');
  dispatch({ type: 'SET_OFFLINE', isOffline: true });
});

// ─── Display events ──────────────────────────────────────────────────

display.addEventListener('change', () => {
  if (display.on) {
    render();
  }
});

// ─── Physical Button Handlers (Sense 2 has 1 button + touch) ─────────

// These would be wired via addEventListener on button elements in index.gui
// For the spike, document the intended mapping:

/**
 * Button / Touch Mapping:
 *
 * Top-left button press  → LOG_SET (with current weight/reps/RIR from UI)
 * Top-right button press → SKIP_SET / SKIP_REST (contextual)
 * Bottom button press    → FINISH_WORKOUT (long press) / PREVIOUS_EXERCISE (short)
 * Swipe left             → PREVIOUS_EXERCISE
 * Swipe right            → SKIP_EXERCISE
 * Tap +/- weight          → ADJUST_WEIGHT
 * Tap +/- reps            → ADJUST_REPS
 * Tap RIR selector        → ADJUST_RIR
 */

// ─── Render ──────────────────────────────────────────────────────────

function render(): void {
  if (!display.on) return;

  // In production: update SVG text/rect elements in index.gui
  // For the spike: log the current state
  console.log(`[app] State: ${state.state} | Ex: ${state.currentExerciseIndex} | Set: ${state.currentSetIndex}`);

  if (state.toast) {
    console.log(`[app] Toast: ${state.toast}`);
  }
}

// ─── Startup ─────────────────────────────────────────────────────────

console.log(`[app] Hevy Companion starting on ${device.modelName} (${device.modelId})`);

// Auto-load plan on startup
dispatch({ type: 'LOAD_PLAN' });
