import React, { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
import ShireScanBridgeClient, { DEFAULT_URL } from '@/lib/ShireScanBridgeClient';
import { appConfig } from '@/lib/appConfig';
import { useShireModule } from '@/context/ShireModuleContext';

const ScannerContext = createContext(null);

const initialStatus = {
  agentState: 'offline',
  bridgeState: 'offline',
  kinectState: 'not_detected',
  operation: 'idle',
  progress: 0,
  activeProjectId: null,
  activeProjectName: null,
  lastSuccessfulScan: null,
  warning: null,
  error: null,
  health: null,
  device: null,
  capabilities: null
};

function legacyStatus(state) {
  if (state.operation === 'capturing') return 'scanning';
  if (state.operation === 'paused') return 'paused';
  if (state.operation === 'processing' || state.operation === 'exporting') return 'processing';
  if (state.operation === 'calibrating') return 'calibrating';
  if (state.agentState === 'failed' || state.bridgeState === 'failed' || state.kinectState === 'failed') return 'failed';
  if (state.warning) return 'warning';
  if (state.kinectState === 'ready') return 'ready';
  if (state.bridgeState === 'connected') return 'connected';
  if (state.bridgeState === 'connecting') return 'pairing';
  if (state.kinectState === 'not_detected') return 'kinect_unavailable';
  return 'offline';
}

export function ScannerProvider({ children }) {
  const shire = useShireModule();
  const shireClient = shire?.client;
  const [bridgeUrl, setBridgeUrl] = useState(localStorage.getItem('shire_bridge_url') || appConfig.scanBridgeBaseUrl || DEFAULT_URL);
  const [scanState, setScanState] = useState(initialStatus);
  const [demo, setDemo] = useState(false);
  const bridgeClient = useMemo(() => new ShireScanBridgeClient(bridgeUrl), [bridgeUrl]);

  const refresh = useCallback(async () => {
    if (demo) return null;
    if (appConfig.mode === 'SHIRE_MODULE') {
      if (!shireClient) throw new Error('SHIRE_AGENT_CONNECTION_UNAVAILABLE');
      const result = await shireClient.getStatus();
      const next = { ...initialStatus, ...result };
      setScanState(next);
      return next;
    }

    const [health, device, capabilities] = await Promise.all([
      bridgeClient.health(),
      bridgeClient.device(),
      bridgeClient.capabilities().catch(() => null)
    ]);
    const depthReady = Boolean(health?.depth_stream || health?.depthStream || device?.depth_stream_ready);
    const next = {
      ...initialStatus,
      agentState: 'online',
      bridgeState: 'connected',
      kinectState: depthReady ? 'ready' : (device ? 'initialising' : 'not_detected'),
      health,
      device,
      capabilities
    };
    setScanState(next);
    return next;
  }, [bridgeClient, demo, shireClient]);

  useEffect(() => {
    if (appConfig.mode !== 'SHIRE_MODULE' || demo) return undefined;
    refresh().catch((error) => setScanState((current) => ({ ...current, agentState: 'offline', error: error.message })));
    const timer = window.setInterval(() => {
      refresh().catch((error) => setScanState((current) => ({ ...current, agentState: 'offline', error: error.message })));
    }, appConfig.statusPollMs);
    return () => window.clearInterval(timer);
  }, [demo, refresh]);

  const saveUrl = (url) => {
    localStorage.setItem('shire_bridge_url', url);
    setBridgeUrl(url);
    setScanState(initialStatus);
  };

  const performAction = useCallback(async (action, parameters = {}, requiresConfirmation = true) => {
    if (demo) throw new Error('DEMO_MODE_HAS_NO_REAL_HARDWARE_ACTIONS');
    if (appConfig.mode === 'SHIRE_MODULE') {
      if (!shireClient) throw new Error('SHIRE_AGENT_CONNECTION_UNAVAILABLE');
      const result = await shireClient.performAction({
        actionId: crypto.randomUUID(),
        action,
        projectId: parameters.projectId,
        parameters,
        requiresConfirmation
      });
      await refresh().catch(() => {});
      return result;
    }

    const projectId = parameters.projectId;
    if (!projectId && !['open_dashboard', 'new_scan'].includes(action)) throw new Error('PROJECT_ID_REQUIRED');
    const bridgeActions = {
      start_capture: () => bridgeClient.capture(projectId, 'start', parameters),
      pause_capture: () => bridgeClient.capture(projectId, 'pause', parameters),
      resume_capture: () => bridgeClient.capture(projectId, 'resume', parameters),
      finish_capture: () => bridgeClient.capture(projectId, 'finish', parameters),
      cancel_capture: () => bridgeClient.capture(projectId, 'cancel', parameters),
      process_scan: () => bridgeClient.process(projectId, parameters)
    };
    if (!bridgeActions[action]) throw new Error('ACTION_REQUIRES_SHIRE_AGENT');
    const result = await bridgeActions[action]();
    await refresh().catch(() => {});
    return result;
  }, [bridgeClient, demo, refresh, shireClient]);

  const reconnect = useCallback(async () => {
    if (demo) return null;
    if (appConfig.mode === 'SHIRE_MODULE') {
      if (!shireClient) throw new Error('SHIRE_AGENT_CONNECTION_UNAVAILABLE');
      await shireClient.restart();
    }
    return refresh();
  }, [demo, refresh, shireClient]);

  const setDemoMode = (enabled) => {
    setDemo(Boolean(enabled));
    setScanState(enabled ? {
      ...initialStatus,
      agentState: 'online',
      bridgeState: 'connected',
      kinectState: 'ready',
      warning: 'DEMO SCANNER MODE'
    } : initialStatus);
  };

  const value = {
    bridgeUrl,
    saveUrl,
    bridgeClient,
    client: bridgeClient,
    scanState,
    status: legacyStatus(scanState),
    device: scanState.device,
    demo,
    setDemo: setDemoMode,
    refresh,
    test: refresh,
    reconnect,
    performAction,
    setScanState
  };

  return <ScannerContext.Provider value={value}>{children}</ScannerContext.Provider>;
}

export const useScanner = () => useContext(ScannerContext);
