import { writable, derived } from 'svelte/store';
import { fetchValueSetByKey } from '$lib/api/valuesets.js';
import { error as toastError } from '$lib/utils/toast.js';

/**
 * ValueSets store - in-memory cache for system ValueSets
 * Note: Backend handles caching, this is just for reducing API calls during session
 */

// Store structure: { [key]: { items: [], loaded: boolean, loading: boolean, error: string|null } }
function createValueSetsStore() {
  const { subscribe, set, update } = writable({});
  
  // Keep track of in-flight requests to prevent duplicates
  const inflightRequests = new Map();

  return {
    subscribe,

    /**
     * Load a value set by key (fetch if not in cache)
     * @param {string} key - Value set key
     * @returns {Promise<Array>} - Array of value set items
     */
    async load(key) {
      // If there's already an in-flight request, return its promise
      if (inflightRequests.has(key)) {
        return inflightRequests.get(key);
      }

      // Check if already loaded in cache
      let cacheState = null;
      subscribe((state) => { cacheState = state; })();
      
      if (cacheState?.[key]?.loaded) {
        return cacheState[key].items;
      }

      // Create the fetch promise
      const fetchPromise = (async () => {
        // Mark as loading
        update((cache) => ({
          ...cache,
          [key]: { items: [], loaded: false, loading: true, error: null },
        }));

        try {
          const response = await fetchValueSetByKey(key);
          
          if (response.status === 'success' && response.data) {
            // Handle both response.data being an array or having an Items property
            let items = Array.isArray(response.data) ? response.data : (response.data.Items || []);
            
            // Sort by Sequence if available
            items.sort((a, b) => (a.Sequence || 0) - (b.Sequence || 0));
            
            update((cache) => ({
              ...cache,
              [key]: { items, loaded: true, loading: false, error: null },
            }));
            
            return items;
          } else {
            throw new Error(response.message || 'Failed to load value set');
          }
        } catch (err) {
          const errorMessage = err.message || `Failed to load value set: ${key}`;
          console.error('valuesets: error for', key, ':', err);
          
          update((cache) => ({
            ...cache,
            [key]: { items: [], loaded: false, loading: false, error: errorMessage },
          }));
          
          toastError(errorMessage);
          return [];
        } finally {
          inflightRequests.delete(key);
        }
      })();

      inflightRequests.set(key, fetchPromise);
      return fetchPromise;
    },

    /**
     * Get value set items (load if needed)
     * @param {string} key - Value set key
     * @returns {Promise<Array>}
     */
    async get(key) {
      return this.load(key);
    },

    /**
     * Get value set items synchronously (returns cached data or empty array)
     * @param {string} key - Value set key
     * @returns {Array}
     */
    getSync(key) {
      let items = [];
      subscribe((cache) => {
        items = cache[key]?.items || [];
      })();
      return items;
    },

    /**
     * Check if value set is loaded
     * @param {string} key - Value set key
     * @returns {boolean}
     */
    isLoaded(key) {
      let loaded = false;
      subscribe((cache) => {
        loaded = cache[key]?.loaded || false;
      })();
      return loaded;
    },

    /**
     * Check if value set is loading
     * @param {string} key - Value set key
     * @returns {boolean}
     */
    isLoading(key) {
      let loading = false;
      subscribe((cache) => {
        loading = cache[key]?.loading || false;
      })();
      return loading;
    },

    /**
     * Clear all cached value sets
     */
    clear() {
      set({});
    },

    /**
     * Clear a specific value set from cache
     * @param {string} key - Value set key
     */
    clearKey(key) {
      update((cache) => {
        const newCache = { ...cache };
        delete newCache[key];
        return newCache;
      });
    },

    /**
     * Reload a value set (clear cache and fetch fresh)
     * @param {string} key - Value set key
     * @returns {Promise<Array>}
     */
    async reload(key) {
      this.clearKey(key);
      return this.load(key);
    },
  };
}

export const valueSets = createValueSetsStore();

/**
 * Derived store to get all loaded value set keys
 */
export const loadedValueSetKeys = derived(valueSets, ($valueSets) => {
  return Object.keys($valueSets).filter((key) => $valueSets[key].loaded);
});

/**
 * Create a derived store for a specific value set
 * @param {string} key - Value set key
 * @returns {import('svelte/store').Readable}
 */
export function getValueSetStore(key) {
  return derived(valueSets, ($valueSets) => {
    return $valueSets[key] || { items: [], loaded: false, loading: false, error: null };
  });
}
