/**
 * State Invalidation Utilities
 * FE-STATE-004: Invalidate stale state when data changes
 *
 * Provides utilities for invalidating cached state, queries, and stores
 * when data changes on the server or locally
 */

import { responseCache } from '@/services/responseCache';
import { logger } from './logger';
import { getQueryClient } from './queryClientSingleton';

/**
 * Types of state that can be invalidated
 */
export type InvalidationTarget =
  | 'cache' // Response cache
  | 'queries' // TanStack Query cache
  | 'stores' // Zustand stores
  | 'all'; // All of the above

/**
 * Resource types for granular invalidation
 */
export type ResourceType =
  | 'tracks'
  | 'playlists'
  | 'users'
  | 'conversations'
  | 'roles'
  | 'library'
  | 'auth'
  | 'ui'
  | 'all';

/**
 * Options for state invalidation
 */
export interface InvalidationOptions {
  /** Target to invalidate */
  target?: InvalidationTarget;
  /** Resource type to invalidate */
  resourceType?: ResourceType;
  /** Specific resource ID */
  resourceId?: string;
  /** Whether to invalidate all state */
  invalidateAll?: boolean;
  /** Query keys to invalidate (for TanStack Query) */
  queryKeys?: (string | number)[][];
  /** Store names to invalidate (for Zustand stores) */
  storeNames?: string[];
}

/**
 * FE-STATE-004: Invalidate stale state
 *
 * Invalidates cached state, queries, and stores based on the provided options.
 * This should be called after mutations or when data changes are detected.
 *
 * @param options Invalidation options
 *
 * @example
 * ```typescript
 * // Invalidate all cache for tracks
 * invalidateState({ resourceType: 'tracks', target: 'cache' });
 *
 * // Invalidate specific playlist
 * invalidateState({ resourceType: 'playlists', resourceId: '123', target: 'all' });
 *
 * // Invalidate after mutation
 * await updatePlaylist(id, data);
 * invalidateState({ resourceType: 'playlists', resourceId: id });
 * ```
 */
export function invalidateState(options: InvalidationOptions = {}): void {
  const {
    target = 'all',
    resourceType,
    resourceId,
    invalidateAll = false,
    queryKeys = [],
    storeNames = [],
  } = options;

  try {
    // Invalidate response cache
    if (target === 'cache' || target === 'all') {
      if (invalidateAll) {
        responseCache.clear();
        logger.debug('[StateInvalidation] Cleared all response cache');
      } else if (resourceType) {
        invalidateCacheByResource(resourceType, resourceId);
      }
    }

    // Invalidate TanStack Query cache
    if (target === 'queries' || target === 'all') {
      invalidateQueries(queryKeys, resourceType, resourceId);
    }

    // Invalidate Zustand stores
    if (target === 'stores' || target === 'all') {
      invalidateStores(storeNames, resourceType, resourceId);
    }

    logger.debug('[StateInvalidation] State invalidated', {
      target,
      resourceType,
      resourceId,
      invalidateAll,
    });
  } catch (error) {
    logger.error('[StateInvalidation] Error invalidating state', {
      error: String(error),
    });
  }
}

/**
 * Invalidate cache by resource type
 */
function invalidateCacheByResource(
  resourceType: ResourceType,
  resourceId?: string,
): void {
  const patterns: Record<ResourceType, string[]> = {
    tracks: ['/tracks', '/library/tracks'],
    playlists: ['/playlists'],
    users: ['/users', '/auth/me'],
    conversations: ['/conversations'],
    roles: ['/roles'],
    library: ['/library', '/tracks'],
    auth: ['/auth'],
    ui: [],
    all: [],
  };

  if (resourceType === 'all') {
    responseCache.clear();
    return;
  }

  const patternsToInvalidate = patterns[resourceType] || [];

  for (const pattern of patternsToInvalidate) {
    responseCache.invalidate(pattern);
  }

  // If resourceId is provided, invalidate specific resource
  if (resourceId) {
    for (const pattern of patternsToInvalidate) {
      responseCache.invalidate(`${pattern}/${resourceId}`);
    }
  }
}

/**
 * Invalidate TanStack Query queries
 * Action 4.6.1.5: Updated to use QueryClient directly instead of custom events
 */
function invalidateQueries(
  queryKeys: (string | number)[][],
  resourceType?: ResourceType,
  resourceId?: string,
): void {
  const queryClient = getQueryClient();
  
  if (!queryClient) {
    logger.warn('[StateInvalidation] QueryClient not available, falling back to event system');
    // Fallback to event system if QueryClient not available
    if (typeof window !== 'undefined') {
      const event = new CustomEvent('veza:invalidate-queries', {
        detail: {
          queryKeys,
          resourceType,
          resourceId,
        },
      });
      window.dispatchEvent(event);
    }
    return;
  }

  // Invalidate specific query keys
  if (queryKeys && queryKeys.length > 0) {
    for (const queryKey of queryKeys) {
      queryClient.invalidateQueries({ queryKey });
    }
  }

  // Invalidate by resource type
  if (resourceType) {
    const resourceQueryKeys: Record<ResourceType, (string | number)[][]> = {
      tracks: [['tracks'], ['track'], ['library']],
      playlists: [['playlists'], ['playlist']],
      users: [['users'], ['user'], ['auth'], ['userProfile']],
      conversations: [['conversations'], ['conversation'], ['chat'], ['chatConversations']],
      roles: [['roles'], ['role']],
      library: [['library'], ['tracks'], ['favorites'], ['libraryItems']],
      auth: [['auth'], ['user']],
      ui: [],
      all: [],
    };

    const keys = resourceQueryKeys[resourceType] || [];

    for (const key of keys) {
      queryClient.invalidateQueries({
        queryKey: resourceId ? [...key, resourceId] : key,
      });
    }
  }

  logger.debug('[StateInvalidation] Invalidated React Query cache', {
    queryKeys,
    resourceType,
    resourceId,
  });
}

/**
 * Invalidate Zustand stores
 */
function invalidateStores(
  storeNames: string[],
  resourceType?: ResourceType,
  resourceId?: string,
): void {
  // Map resource types to store names
  const resourceToStores: Record<ResourceType, string[]> = {
    tracks: ['library'],
    playlists: ['library'],
    users: ['auth'],
    conversations: ['chat'],
    roles: [],
    library: ['library'],
    auth: ['auth'],
    ui: ['ui'],
    all: ['auth', 'library', 'chat', 'ui'],
  };

  const storesToInvalidate =
    storeNames.length > 0
      ? storeNames
      : resourceType
        ? resourceToStores[resourceType] || []
        : [];

  for (const storeName of storesToInvalidate) {
    invalidateStore(storeName, resourceType, resourceId).catch((error) => {
      logger.warn(
        `[StateInvalidation] Failed to invalidate store ${storeName}`,
        { error: String(error) },
      );
    });
  }
}

/**
 * Invalidate a specific store
 * Action 4.6.1.5: Updated for React Query migration - most stores no longer need invalidation
 */
async function invalidateStore(
  storeName: string,
  _resourceType?: ResourceType,
  _resourceId?: string,
): Promise<void> {
  try {
    switch (storeName) {
      case 'auth': {
        // Use dynamic import instead of require
        const { useAuthStore } = await import(
          '@/features/auth/store/authStore'
        );
        // Refresh user data
        useAuthStore.getState().refreshUser?.();
        break;
      }

      case 'library': {
        // Action 4.1.2.4: Library Store domain data migrated to React Query
        // No need to clear items - React Query handles cache invalidation
        // Library Store now only contains UI state (filters)
        // React Query cache invalidation will handle refetching
        break;
      }

      case 'chat': {
        // Action 4.5.1.5: Chat store moved to feature store - conversations are managed via React Query
        // No need to refetch here - React Query will handle invalidation
        // Conversations are fetched via React Query in ChatSidebar component
        // React Query cache invalidation will handle refetching
        break;
      }

      case 'ui':
        // UI store doesn't need invalidation as it's user preferences
        break;

      default:
        logger.warn(`[StateInvalidation] Unknown store: ${storeName}`);
    }
  } catch (error) {
    logger.error(`[StateInvalidation] Error invalidating store ${storeName}`, {
      error: String(error),
    });
  }
}

/**
 * FE-STATE-004: Helper to invalidate state after a mutation
 *
 * This is a convenience function that automatically determines what to invalidate
 * based on the mutation endpoint.
 *
 * @param url The mutation URL
 * @param method The HTTP method
 *
 * @example
 * ```typescript
 * // In apiClient interceptor
 * if (isMutation) {
 *   invalidateStateAfterMutation(response.config.url, method);
 * }
 * ```
 */
export function invalidateStateAfterMutation(
  url: string | undefined,
  _method: string,
): void {
  if (!url) {
    return;
  }

  // Determine resource type from URL
  let resourceType: ResourceType | undefined;
  let resourceId: string | undefined;

  if (url.includes('/tracks/')) {
    resourceType = 'tracks';
    const match = url.match(/\/tracks\/([^/]+)/);
    resourceId = match ? match[1] : undefined;
  } else if (url.includes('/playlists/')) {
    resourceType = 'playlists';
    const match = url.match(/\/playlists\/([^/]+)/);
    resourceId = match ? match[1] : undefined;
  } else if (url.includes('/users/') || url.includes('/auth/')) {
    resourceType = 'users';
    const match = url.match(/\/(users|auth)\/([^/]+)/);
    resourceId = match ? match[2] : undefined;
  } else if (url.includes('/conversations/')) {
    resourceType = 'conversations';
    const match = url.match(/\/conversations\/([^/]+)/);
    resourceId = match ? match[1] : undefined;
  } else if (url.includes('/roles/')) {
    resourceType = 'roles';
    const match = url.match(/\/roles\/([^/]+)/);
    resourceId = match ? match[1] : undefined;
  }

  if (resourceType) {
    invalidateState({
      resourceType,
      resourceId,
      target: 'all',
    });
  } else {
    // If we can't determine the resource type, invalidate all cache
    invalidateState({
      target: 'cache',
      invalidateAll: true,
    });
  }
}
