/**
 * App context hook for accessing AppService and app-level functions.
 */

import React, { createContext, useContext, useState, useCallback, type ReactNode } from 'react';
import { AppService } from '../../services/app.js';
import type { AppConfig } from '../../app.js';
import type { AppContextType, DialogState } from '../types.js';

/**
 * App context.
 */
const AppContext = createContext<AppContextType | null>(null);

/**
 * Dialog context for managing modal dialogs.
 */
interface DialogContextType {
  dialog: DialogState | null;
  setDialog: (dialog: DialogState | null) => void;
}

const DialogContext = createContext<DialogContextType | null>(null);

/**
 * Status context for managing status bar.
 */
interface StatusContextType {
  status: string;
  setStatus: (status: string) => void;
}

const StatusContext = createContext<StatusContextType | null>(null);

/**
 * App provider props.
 */
interface AppProviderProps {
  children: ReactNode;
  config: AppConfig;
  onExit: () => void;
}

/**
 * App provider component.
 * Provides AppService, dialog management, and app-level functions to children.
 */
export function AppProvider({
  children,
  config,
  onExit,
}: AppProviderProps): React.ReactElement {
  const [appService, setAppService] = useState<AppService | null>(null);
  const [dialog, setDialog] = useState<DialogState | null>(null);
  const [status, setStatusState] = useState<string>('Ready');
  const [isWalletInitialized, setWalletInitialized] = useState(false);

  /**
   * Initialize wallet with seed phrase and create AppService.
   */
  const initializeWallet = useCallback(async (seed: string) => {
    try {
      // Create the AppService with the seed
      const service = await AppService.create(seed, {
        syncServerUrl: config.syncServerUrl,
        engineConfig: {
          databasePath: config.databasePath,
          databaseFilename: config.databaseFilename,
        },
        invitationStoragePath: config.invitationStoragePath,
      });

      // Start the AppService (loads existing invitations)
      await service.start();

      // Set the service and mark as initialized
      setAppService(service);
      setWalletInitialized(true);
    } catch (error) {
      // Re-throw the error so the caller can handle it
      throw error;
    }
  }, [config]);

  /**
   * Show an error dialog.
   */
  const showError = useCallback((message: string) => {
    setDialog({
      visible: true,
      type: 'error',
      message,
      onCancel: () => setDialog(null),
    });
  }, []);

  /**
   * Show an info dialog.
   */
  const showInfo = useCallback((message: string) => {
    setDialog({
      visible: true,
      type: 'info',
      message,
      onCancel: () => setDialog(null),
    });
  }, []);

  /**
   * Show a confirmation dialog and wait for user response.
   */
  const confirm = useCallback((message: string): Promise<boolean> => {
    return new Promise((resolve) => {
      setDialog({
        visible: true,
        type: 'confirm',
        message,
        onConfirm: () => {
          setDialog(null);
          resolve(true);
        },
        onCancel: () => {
          setDialog(null);
          resolve(false);
        },
      });
    });
  }, []);

  /**
   * Update status bar message.
   */
  const setStatus = useCallback((message: string) => {
    setStatusState(message);
  }, []);

  const appValue: AppContextType = {
    appService,
    initializeWallet,
    isWalletInitialized,
    config,
    showError,
    showInfo,
    confirm,
    exit: onExit,
    setStatus,
  };

  const dialogValue: DialogContextType = {
    dialog,
    setDialog,
  };

  const statusValue: StatusContextType = {
    status,
    setStatus,
  };

  return (
    <AppContext.Provider value={appValue}>
      <DialogContext.Provider value={dialogValue}>
        <StatusContext.Provider value={statusValue}>
          {children}
        </StatusContext.Provider>
      </DialogContext.Provider>
    </AppContext.Provider>
  );
}

/**
 * Hook to access app context.
 * @returns App context
 * @throws Error if used outside AppProvider
 */
export function useAppContext(): AppContextType {
  const context = useContext(AppContext);
  if (!context) {
    throw new Error('useAppContext must be used within an AppProvider');
  }
  return context;
}

/**
 * Hook to access dialog context.
 * @returns Dialog context
 */
export function useDialog(): DialogContextType {
  const context = useContext(DialogContext);
  if (!context) {
    throw new Error('useDialog must be used within an AppProvider');
  }
  return context;
}

/**
 * Hook to access status context.
 * @returns Status context
 */
export function useStatus(): StatusContextType {
  const context = useContext(StatusContext);
  if (!context) {
    throw new Error('useStatus must be used within an AppProvider');
  }
  return context;
}
