/**
 * Pi Multi-FX Pedal — State Hook
 *
 * API helpers, WebSocket real-time updates, and pedal state management.
 * Ported and organized from frontend-react/App.jsx.
 */

import { useState, useRef, useEffect, useCallback } from 'react';
import type { PedalState, PresetListResponse } from '../types';

// ── API Base ──────────────────────────────────────────────────

const API = window.location.origin;
const WS_URL = API.replace(/^http/, 'ws') + '/ws';

// ── API Helpers ───────────────────────────────────────────────

export async function apiGet<T>(path: string): Promise<T> {
  const r = await fetch(`${API}${path}`);
  if (!r.ok) throw new Error(`${path} => ${r.status}`);
  return r.json();
}

export async function apiPost<T>(path: string, data?: unknown): Promise<T> {
  const r = await fetch(`${API}${path}`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: data != null ? JSON.stringify(data) : undefined,
  });
  if (!r.ok) throw new Error(`${path} => ${r.status}`);
  return r.json();
}

export async function apiPut<T>(path: string, data: unknown): Promise<T> {
  const r = await fetch(`${API}${path}`, {
    method: 'PUT',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(data),
  });
  if (!r.ok) throw new Error(`${path} => ${r.status}`);
  return r.json();
}

export async function apiDelete<T>(path: string): Promise<T> {
  const r = await fetch(`${API}${path}`, { method: 'DELETE' });
  if (!r.ok) throw new Error(`${path} => ${r.status}`);
  return r.json();
}

export async function apiUpload<T>(path: string, file: File): Promise<T> {
  const fd = new FormData();
  fd.append('file', file);
  const r = await fetch(`${API}${path}`, { method: 'POST', body: fd });
  if (!r.ok) throw new Error(`${path} => ${r.status}`);
  return r.json();
}

// ── usePedalState Hook ────────────────────────────────────────

export interface PedalStateResult {
  state: PedalState | null;
  connected: boolean;
  refresh: () => void;
}

export function usePedalState(): PedalStateResult {
  const [state, setState] = useState<PedalState | null>(null);
  const [connected, setConnected] = useState(false);
  const wsRef = useRef<WebSocket | null>(null);
  const pollRef = useRef<ReturnType<typeof setInterval> | null>(null);

  useEffect(() => {
    // Fetch initial state
    apiGet<PedalState>('/api/state')
      .then(s => { setState(s); setConnected(true); })
      .catch(() => { setConnected(false); });

    // WebSocket for real-time updates
    let reconnectTimer: ReturnType<typeof setTimeout>;

    function connect() {
      try {
        const ws = new WebSocket(WS_URL);
        ws.onmessage = (e) => {
          try {
            const msg = JSON.parse(e.data);
            if (msg.type === 'connected' || msg.type === 'state') {
              setState(msg.state);
              setConnected(true);
            }
            if (msg.type === 'preset_changed' && msg.state) setState(msg.state);
            if (msg.type === 'bypass_changed') {
              setState(prev => prev ? { ...prev, bypass: msg.bypass } : prev);
            }
            if (msg.type === 'tuner_changed') {
              setState(prev => prev ? { ...prev, tuner_enabled: msg.tuner_enabled } : prev);
            }
            if (msg.type === 'routing_changed') {
              setState(prev => prev ? {
                ...prev,
                routing_mode: msg.routing_mode,
                routing_breakpoint: msg.routing_breakpoint,
              } : prev);
            }
            if (msg.type === 'model_loaded' || msg.type === 'ir_loaded') {
              apiGet<PedalState>('/api/state').then(s => setState(s));
            }
          } catch {
            // ignore parse errors
          }
        };
        ws.onclose = () => {
          setConnected(false);
          reconnectTimer = setTimeout(connect, 3000);
        };
        ws.onerror = () => ws.close();
        wsRef.current = ws;
      } catch {
        reconnectTimer = setTimeout(connect, 3000);
      }
    }
    connect();

    // Polling fallback every 5s
    pollRef.current = setInterval(() => {
      apiGet<PedalState>('/api/state')
        .then(s => { setState(s); setConnected(true); })
        .catch(() => {});
    }, 5000);

    return () => {
      if (pollRef.current) clearInterval(pollRef.current);
      clearTimeout(reconnectTimer);
      if (wsRef.current) wsRef.current.close();
    };
  }, []);

  const refresh = useCallback(() => {
    apiGet<PedalState>('/api/state')
      .then(s => { setState(s); setConnected(true); })
      .catch(() => {});
  }, []);

  return { state, connected, refresh };
}

// ── Preset helpers ────────────────────────────────────────────

export async function fetchPresets(): Promise<PresetListResponse> {
  return apiGet<PresetListResponse>('/api/presets');
}

export async function activatePreset(bank: number, program: number): Promise<void> {
  await apiPost(`/api/presets/${bank}/${program}/activate`);
}
