'use client';

import { useContext, useMemo } from 'react';
import { ContainerContext } from '../providers/ContainerProvider';

/**
 * Primary injection hook - gets a service by token
 *
 * @example
 * const leagueService = useInject(LEAGUE_SERVICE_TOKEN);
 */
export function useInject<T extends symbol>(token: T): T extends { type: infer U } ? U : unknown {
  const container = useContext(ContainerContext);
  
  if (!container) {
    throw new Error('useInject must be used within ContainerProvider');
  }

  return useMemo(() => {
    try {
      return container.get(token) as T extends { type: infer U } ? U : unknown;
    } catch (error) {
      console.error(`Failed to resolve token ${token.toString()}:`, error);
      throw error;
    }
  }, [container, token]);
}

/**
 * Hook to get multiple services at once
 * 
 * @example
 * const [leagueService, driverService] = useInjectMany([
 *   LEAGUE_SERVICE_TOKEN,
 *   DRIVER_SERVICE_TOKEN
 * ]);
 */
export function useInjectMany<T extends any[]>(tokens: symbol[]): T {
  const container = useContext(ContainerContext);
  
  if (!container) {
    throw new Error('useInjectMany must be used within ContainerProvider');
  }

  return useMemo(() => {
    return tokens.map(token => container.get(token)) as T;
  }, [container, tokens]);
}

/**
 * Hook to get all services of a given type (tag-based resolution)
 * 
 * @example
 * const allServices = useInjectAll<Service>('Service');
 */
export function useInjectAll<T>(serviceIdentifier: string | symbol): T[] {
  const container = useContext(ContainerContext);
  
  if (!container) {
    throw new Error('useInjectAll must be used within ContainerProvider');
  }

  return useMemo(() => {
    return container.getAll<T>(serviceIdentifier);
  }, [container, serviceIdentifier]);
}

/**
 * Hook for optional service injection (returns null if not found)
 * 
 * @example
 * const optionalService = useInjectOptional(MAYBE_SERVICE_TOKEN);
 */
export function useInjectOptional<T>(token: symbol): T | null {
  const container = useContext(ContainerContext);
  
  return useMemo(() => {
    if (!container) {
      return null;
    }
    try {
      return container.get<T>(token);
    } catch {
      return null;
    }
  }, [container, token]);
}