/**
 * KRA - Dictionary Model (Zustand Store)
 * Dictionary cache and lookup management
 */
import { create } from 'zustand';
import {
  DictionaryItem,
  filterTreeByDepth,
  flattenTree,
  normalizeTreeData,
  findNodeByValue,
  buildCacheKey,
} from '@/utils/dictionary';

interface DictionaryState {
  dictionaryMap: Record<string, DictionaryItem[]>;
  loading: Record<string, boolean>;
}

interface DictionaryActions {
  setDictionary: (key: string, data: DictionaryItem[]) => void;
  getDictionary: (
    type: string,
    fetchFn: (type: string) => Promise<DictionaryItem[]>,
    depth?: number,
    value?: any
  ) => Promise<DictionaryItem[]>;
  getDictionarySync: (type: string, depth?: number) => DictionaryItem[];
  clearDictionary: (type?: string) => void;
  setLoading: (key: string, loading: boolean) => void;
}

export const useDictionaryStore = create<DictionaryState & DictionaryActions>((set, get) => ({
  dictionaryMap: {},
  loading: {},

  setDictionary: (key, data) => {
    set((state) => ({
      dictionaryMap: { ...state.dictionaryMap, [key]: data },
    }));
  },

  getDictionary: async (type, fetchFn, depth = 0, value = null) => {
    const cacheKey = buildCacheKey(type, depth, value);
    const { dictionaryMap, setDictionary, setLoading } = get();

    // Return cached data if exists
    if (dictionaryMap[cacheKey] && dictionaryMap[cacheKey].length > 0) {
      return dictionaryMap[cacheKey];
    }

    // Set loading state
    setLoading(cacheKey, true);

    try {
      // Fetch tree data
      const treeData = await fetchFn(type);

      if (!treeData || treeData.length === 0) {
        setLoading(cacheKey, false);
        return [];
      }

      let resultData: DictionaryItem[];

      // If value is provided, find specific node's children
      if (value !== null && value !== undefined) {
        const targetNodeChildren = findNodeByValue(treeData, value, 1, depth);

        if (targetNodeChildren !== null) {
          if (depth === 0) {
            resultData = targetNodeChildren;
          } else {
            resultData = flattenTree(targetNodeChildren);
          }
        } else {
          resultData = [];
        }
      } else {
        // No value filter
        if (depth === 0) {
          resultData = normalizeTreeData(treeData);
        } else {
          const filteredData = filterTreeByDepth(treeData, 1, depth);
          resultData = flattenTree(filteredData);
        }
      }

      setDictionary(cacheKey, resultData);
      setLoading(cacheKey, false);
      return resultData;
    } catch (error) {
      console.error('Failed to fetch dictionary:', error);
      setLoading(cacheKey, false);
      return [];
    }
  },

  getDictionarySync: (type, depth = 0) => {
    const cacheKey = buildCacheKey(type, depth);
    const { dictionaryMap } = get();
    return dictionaryMap[cacheKey] || [];
  },

  clearDictionary: (type) => {
    if (type) {
      set((state) => {
        const newMap = { ...state.dictionaryMap };
        Object.keys(newMap).forEach((key) => {
          if (key.startsWith(type)) {
            delete newMap[key];
          }
        });
        return { dictionaryMap: newMap };
      });
    } else {
      set({ dictionaryMap: {} });
    }
  },

  setLoading: (key, loading) => {
    set((state) => ({
      loading: { ...state.loading, [key]: loading },
    }));
  },
}));

// Helper hooks
export const useDictionaryMap = () => useDictionaryStore((state) => state.dictionaryMap);
export const useDictionaryLoading = (key: string) =>
  useDictionaryStore((state) => state.loading[key] || false);

export default useDictionaryStore;
