/**
 * Optimistic Store Updates Utility
 * FE-STATE-005: Update Zustand stores optimistically before API confirmation
 * 
 * Provides utilities for implementing optimistic updates in Zustand stores
 * with automatic rollback on error
 */

import { logger } from './logger';

/**
 * Options for optimistic store update
 */
export interface OptimisticStoreUpdateOptions<TState = any, TVariables = any> {
  /** Store getState function */
  getState: () => TState;
  /** Store setState function */
  setState: (updater: (state: TState) => Partial<TState> | TState) => void;
  /** Function to generate optimistic state from current state and variables */
  optimisticUpdate: (state: TState, variables: TVariables) => Partial<TState> | TState;
  /** Function to rollback state on error */
  rollback?: (state: TState, variables: TVariables) => Partial<TState> | TState;
  /** Function to apply server response to state */
  applyResponse?: (state: TState, response: any) => Partial<TState> | TState;
}

/**
 * Result of optimistic update operation
 */
export interface OptimisticUpdateResult<TState = any> {
  /** Snapshot of state before optimistic update */
  previousState: TState;
  /** Function to rollback to previous state */
  rollback: () => void;
  /** Function to apply server response */
  applyResponse: (response: any) => void;
}

/**
 * FE-STATE-005: Create an optimistic update for a Zustand store
 * 
 * This function wraps an API call to update the store optimistically,
 * then applies the server response or rolls back on error.
 * 
 * @param options Configuration for the optimistic update
 * @returns Object with rollback and applyResponse functions
 * 
 * @example
 * ```typescript
 * // In a store action
 * toggleFavorite: async (itemId) => {
 *   const { rollback, applyResponse } = createOptimisticStoreUpdate({
 *     getState: get,
 *     setState: set,
 *     optimisticUpdate: (state, itemId) => ({
 *       items: state.items.map(item =>
 *         item.id === itemId
 *           ? { ...item, is_favorite: !item.is_favorite }
 *           : item
 *       ),
 *     }),
 *   });
 * 
 *   try {
 *     const response = await apiClient.post(`/tracks/${itemId}/favorite`);
 *     applyResponse(response.data);
 *   } catch (error) {
 *     rollback();
 *     throw error;
 *   }
 * }
 * ```
 */
export function createOptimisticStoreUpdate<TState = any, TVariables = any>(
  options: OptimisticStoreUpdateOptions<TState, TVariables>,
): OptimisticUpdateResult<TState> {
  const {
    getState,
    setState,
    optimisticUpdate,
    rollback: customRollback,
    applyResponse: customApplyResponse,
  } = options;

  // Snapshot current state
  const previousState = getState();

  // Apply optimistic update
  setState((state) => {
    const update = optimisticUpdate(state, undefined as TVariables);
    return typeof update === 'function' ? (update as any)(state) : update;
  });

  // Create rollback function
  const rollback = () => {
    if (customRollback) {
      setState((state) => {
        const rollbackState = customRollback(state, undefined as TVariables);
        return typeof rollbackState === 'function' ? (rollbackState as any)(state) : rollbackState;
      });
    } else {
      // Default: restore previous state
      setState(() => previousState);
    }
    logger.debug('[OptimisticStoreUpdate] Rolled back state');
  };

  // Create apply response function
  const applyResponse = (response: any) => {
    if (customApplyResponse) {
      setState((state) => {
        const updatedState = customApplyResponse(state, response);
        return typeof updatedState === 'function' ? (updatedState as any)(state) : updatedState;
      });
    }
    logger.debug('[OptimisticStoreUpdate] Applied server response');
  };

  return {
    previousState,
    rollback,
    applyResponse,
  };
}

/**
 * FE-STATE-005: Wrapper for async store actions with optimistic updates
 * 
 * This is a higher-order function that wraps an async action to add
 * optimistic update support.
 * 
 * @param action The async action function
 * @param options Optimistic update options
 * @returns Wrapped action with optimistic updates
 * 
 * @example
 * ```typescript
 * // In a store
 * toggleFavorite: withOptimisticUpdate(
 *   async (itemId) => {
 *     const response = await apiClient.post(`/tracks/${itemId}/favorite`);
 *     return response.data;
 *   },
 *   {
 *     getState: get,
 *     setState: set,
 *     optimisticUpdate: (state, itemId) => ({
 *       items: state.items.map(item =>
 *         item.id === itemId
 *           ? { ...item, is_favorite: !item.is_favorite }
 *           : item
 *       ),
 *     }),
 *   }
 * ),
 * ```
 */
export function withOptimisticUpdate<TState = any, TVariables = any, TResponse = any>(
  action: (variables: TVariables) => Promise<TResponse>,
  options: Omit<OptimisticStoreUpdateOptions<TState, TVariables>, 'rollback' | 'applyResponse'> & {
    rollback?: (state: TState, variables: TVariables, error: any) => Partial<TState> | TState;
    applyResponse?: (state: TState, variables: TVariables, response: TResponse) => Partial<TState> | TState;
  },
): (variables: TVariables) => Promise<TResponse> {
  return async (variables: TVariables): Promise<TResponse> => {
    const { getState, setState, optimisticUpdate, rollback: customRollback, applyResponse: customApplyResponse } = options;

    // Snapshot current state
    const previousState = getState();

    // Apply optimistic update
    setState((state) => {
      const update = optimisticUpdate(state, variables);
      return typeof update === 'function' ? (update as any)(state) : update;
    });

    try {
      // Execute the action
      const response = await action(variables);

      // Apply server response
      if (customApplyResponse) {
        setState((state) => {
          const updatedState = customApplyResponse(state, variables, response);
          return typeof updatedState === 'function' ? (updatedState as any)(state) : updatedState;
        });
      }

      return response;
    } catch (error) {
      // Rollback on error
      if (customRollback) {
        setState((state) => {
          const rollbackState = customRollback(state, variables, error);
          return typeof rollbackState === 'function' ? (rollbackState as any)(state) : rollbackState;
        });
      } else {
        // Default: restore previous state
        setState(() => previousState);
      }

      logger.debug('[OptimisticStoreUpdate] Rolled back due to error:', error);
      throw error;
    }
  };
}

/**
 * FE-STATE-005: Helper for array operations with optimistic updates
 * 
 * @example
 * ```typescript
 * // Add item optimistically
 * addItem: withOptimisticArrayUpdate(
 *   async (item) => {
 *     const response = await apiClient.post('/items', item);
 *     return response.data;
 *   },
 *   {
 *     getState: get,
 *     setState: set,
 *     operation: 'add',
 *     getArray: (state) => state.items,
 *     optimisticItem: (state, item) => ({
 *       ...item,
 *       id: `temp-${Date.now()}`,
 *     }),
 *   }
 * ),
 * ```
 */
export interface OptimisticArrayUpdateOptions<TState = any, TItem = any, TVariables = any> {
  getState: () => TState;
  setState: (updater: (state: TState) => Partial<TState> | TState) => void;
  operation: 'add' | 'remove' | 'update';
  getArray: (state: TState) => TItem[];
  setArray: (state: TState, array: TItem[]) => Partial<TState> | TState;
  optimisticItem?: (state: TState, variables: TVariables) => TItem;
  matchItem?: (item: TItem, variables: TVariables) => boolean;
  updateItem?: (item: TItem, variables: TVariables) => TItem;
}

export function withOptimisticArrayUpdate<TState = any, TItem = any, TVariables = any, TResponse = any>(
  action: (variables: TVariables) => Promise<TResponse>,
  options: OptimisticArrayUpdateOptions<TState, TItem, TVariables>,
): (variables: TVariables) => Promise<TResponse> {
  return async (variables: TVariables): Promise<TResponse> => {
    const {
      getState,
      setState,
      operation,
      getArray,
      setArray,
      optimisticItem,
      matchItem,
      updateItem,
    } = options;

    const previousState = getState();
    const previousArray = getArray(previousState);

    // Apply optimistic update
    setState((state) => {
      const currentArray = getArray(state);
      let newArray: TItem[];

      switch (operation) {
        case 'add':
          if (optimisticItem) {
            newArray = [...currentArray, optimisticItem(state, variables)];
          } else {
            newArray = currentArray;
          }
          break;

        case 'remove':
          if (matchItem) {
            newArray = currentArray.filter((item) => !matchItem(item, variables));
          } else {
            newArray = currentArray;
          }
          break;

        case 'update':
          if (matchItem && updateItem) {
            newArray = currentArray.map((item) =>
              matchItem(item, variables) ? updateItem(item, variables) : item,
            );
          } else {
            newArray = currentArray;
          }
          break;

        default:
          newArray = currentArray;
      }

      return setArray(state, newArray);
    });

    try {
      const response = await action(variables);
      // Server response will be applied by the action or can be handled separately
      return response;
    } catch (error) {
      // Rollback
      setState(() => previousState);
      logger.debug('[OptimisticStoreUpdate] Rolled back array operation:', error);
      throw error;
    }
  };
}

