import {
  allExtensionFn,
  generalExtensionFn,
  generalGroupExtensionFn,
  gsapAllExtensionFn,
  gsapExtensionFn,
  gsapGroupExtensionFn,
} from "@/lib/extensionService";
import { activeGroupLibraryFn, libraryConditionsFn, libraryFn } from "@/lib/libraryService";
import {
  disableAllWidget,
  disableGeneralExtension,
  disableGsapExtension,
} from "@/lib/utils";
import {
  activeFullWidgetFn,
  activeGroupWidgetFn,
  activeWidgetFn,
} from "@/lib/widgetService";
import {
  activeAtomicFullWidgetFn,
  activeAtomicGroupWidgetFn,
  activeAtomicWidgetFn,
  groupAtomicWidgetsByCategory,
} from "@/lib/atomicWidgetService";
import {
  activeAtomicFullExtensionFn,
  activeAtomicGroupExtensionFn,
  activeAtomicExtensionFn,
  groupAtomicExtensionsByCategory,
} from "@/lib/atomicExtensionService";
import { applyWizardSetup } from "@/lib/setupPresets";
import { createContext, useCallback, useReducer } from "react";

// Guarantees `.elements` is always an object, even when a category (e.g.
// widgets) has been fully commented out of config.php or otherwise ships
// without an `elements` key — prevents Object.entries()/.map() crashes
// throughout the dashboard (widgets list, search, etc).
const normalizeElements = (data) => {
  const parsed = data ? JSON.parse(JSON.stringify(data)) : {};
  return { ...parsed, elements: parsed.elements || {} };
};

const initialState = {
  allWidgets: normalizeElements(WCF_ADDONS_ADMIN?.addons_config?.widgets),
  allAtomicWidgets: groupAtomicWidgetsByCategory(
    WCF_ADDONS_ADMIN?.addons_config?.atomic_widgets
  ),
  allExtensions: normalizeElements(
    WCF_ADDONS_ADMIN?.addons_config?.extensions
  ),
  allAtomicExtensions: groupAtomicExtensionsByCategory(
    WCF_ADDONS_ADMIN?.addons_config?.atomic_extensions
  ),
  allLibrary: normalizeElements(
    WCF_ADDONS_ADMIN?.addons_config?.integrations?.library
  ),
  activated: WCF_ADDONS_ADMIN?.addons_config || {},
  setupType: "basic",
  notice: [],
  tabKey: "",
  isSkipTerms: true,
};

const reducer = (state, action) => {
  switch (action.type) {
    case "setAllWidgets":
      return { ...state, allWidgets: action.value };
    case "setAllAtomicWidgets":
      return { ...state, allAtomicWidgets: action.value };
    case "setAllExtensions":
      return { ...state, allExtensions: action.value };
    case "setAllAtomicExtensions":
      return { ...state, allAtomicExtensions: action.value };
    case "setActivated":
      return { ...state, activated: action.value };
    case "setLibrary":
      return { ...state, allLibrary: action.value };
    case "setSetupType":
      return { ...state, setupType: action.value };
    case "setNotice":
      return { ...state, notice: action.value };
    case "setTabKey":
      return { ...state, tabKey: action.value };
    case "setIsSkipTerms":
      return { ...state, isSkipTerms: action.value };

    default:
      throw new Error();
  }
};

const useMainContext = (state) => {
  const [mainState, dispatch] = useReducer(reducer, state);

  const setAllWidgets = useCallback((data) => {
    dispatch({
      type: "setAllWidgets",
      value: data,
    });
  }, []);

  const setAllAtomicWidgets = useCallback((data) => {
    dispatch({
      type: "setAllAtomicWidgets",
      value: data,
    });
  }, []);

  const setAllExtensions = useCallback((data) => {
    dispatch({
      type: "setAllExtensions",
      value: data,
    });
  }, []);

  const setAllAtomicExtensions = useCallback((data) => {
    dispatch({
      type: "setAllAtomicExtensions",
      value: data,
    });
  }, []);

  // const setLibrary = useCallback((data) => {
  //   dispatch({
  //     type: "setLibrary",
  //     value: data,
  //   });
  // }, []);

  const setActivated = useCallback((data) => {
    dispatch({
      type: "setActivated",
      value: data,
    });
  }, []);
  const setNotice = useCallback((data) => {
    dispatch({
      type: "setNotice",
      value: data,
    });
  }, []);

  const setTabKey = useCallback((data) => {
    dispatch({
      type: "setTabKey",
      value: data,
    });
  }, []);

  const setIsSkipTerms = useCallback((data) => {
    dispatch({
      type: "setIsSkipTerms",
      value: data,
    });
  }, []);

  const setSetupType = useCallback((data) => {
    if (data && data === "advance") {
      // update widget state
      const widgetResult = disableAllWidget(mainState.allWidgets.elements);
      setAllWidgets({ ...mainState.allWidgets, elements: widgetResult });

      // update extension state
      const gsapResult = disableGsapExtension(
        mainState.allExtensions.elements["gsap-extensions"]
      );
      const generalResult = disableGeneralExtension(
        mainState.allExtensions.elements["general-extensions"]
      );

      setAllExtensions({
        ...mainState.allExtensions,
        elements: {
          "general-extensions": generalResult,
          "gsap-extensions": gsapResult,
        },
      });
    } else {
      // update widget state to default
      setAllWidgets(WCF_ADDONS_ADMIN?.addons_config?.widgets || {});

      // update extension state to default
      setAllExtensions(WCF_ADDONS_ADMIN?.addons_config?.extensions || {});
    }
    dispatch({
      type: "setSetupType",
      value: data,
    });
  }, []);

  const updateActiveWidget = useCallback(
    (data) => {
      activeWidgetFn(mainState.allWidgets, data, dispatch);
    },
    [mainState.allWidgets]
  ); 

  const updateActiveGroupWidget = useCallback(
    (data) => {
      activeGroupWidgetFn(mainState.allWidgets, data, dispatch);
    },
    [mainState.allWidgets]
  );

  const updateActiveFullWidget = useCallback(
    (data) => {
      activeFullWidgetFn(mainState.allWidgets, data, dispatch);
    },
    [mainState.allWidgets]
  );

  // Seeds the wizard's atomic widget / extension steps from the setup type
  // picked on step 1. Kept OUT of setSetupType above: that callback carries an
  // empty dependency array and so reads a `mainState` frozen at first render —
  // harmless for the V3 branches it drives (they re-read the untouched
  // WCF_ADDONS_ADMIN config), but it would seed the atomic steps from a stale
  // snapshot. The steps call these on mount instead, where the state is fresh.
  const applyAtomicWidgetSetup = useCallback(
    (setupType) => {
      dispatch({
        type: "setAllAtomicWidgets",
        value: applyWizardSetup(mainState.allAtomicWidgets, setupType),
      });
    },
    [mainState.allAtomicWidgets]
  );

  const applyAtomicExtensionSetup = useCallback(
    (setupType) => {
      dispatch({
        type: "setAllAtomicExtensions",
        value: applyWizardSetup(mainState.allAtomicExtensions, setupType),
      });
    },
    [mainState.allAtomicExtensions]
  );

  const updateActiveAtomicWidget = useCallback(
    (data) => {
      activeAtomicWidgetFn(mainState.allAtomicWidgets, data, dispatch);
    },
    [mainState.allAtomicWidgets]
  );

  const updateActiveAtomicGroupWidget = useCallback(
    (data) => {
      activeAtomicGroupWidgetFn(mainState.allAtomicWidgets, data, dispatch);
    },
    [mainState.allAtomicWidgets]
  );

  const updateActiveAtomicFullWidget = useCallback(
    (data) => {
      activeAtomicFullWidgetFn(mainState.allAtomicWidgets, data, dispatch);
    },
    [mainState.allAtomicWidgets]
  );

  const updateActiveAtomicExtension = useCallback(
    (data) => {
      activeAtomicExtensionFn(mainState.allAtomicExtensions, data, dispatch);
    },
    [mainState.allAtomicExtensions]
  );

  const updateActiveAtomicGroupExtension = useCallback(
    (data) => {
      activeAtomicGroupExtensionFn(
        mainState.allAtomicExtensions,
        data,
        dispatch
      );
    },
    [mainState.allAtomicExtensions]
  );

  const updateActiveAtomicFullExtension = useCallback(
    (data) => {
      activeAtomicFullExtensionFn(
        mainState.allAtomicExtensions,
        data,
        dispatch
      );
    },
    [mainState.allAtomicExtensions]
  );

  const updateActiveGeneralExtension = useCallback(
    (data) => {
      generalExtensionFn(mainState.allExtensions, data, dispatch);
    },
    [mainState.allExtensions]
  );

  const updateActiveGeneralGroupExtension = useCallback(
    (data) => {
      generalGroupExtensionFn(mainState.allExtensions, data, dispatch);
    },
    [mainState.allExtensions]
  );

  const updateActiveGsapExtension = useCallback(
    (data) => {
      gsapExtensionFn(mainState.allExtensions, data, dispatch);
    },
    [mainState.allExtensions]
  );

  const updateLibrary = useCallback(
    (data) => {
      libraryFn(mainState.allLibrary, data, dispatch);
    },
    [mainState.allLibrary]
  );

  const updateActiveGroupLibrary = useCallback(
    (data) => {
      activeGroupLibraryFn(mainState.allLibrary, data, dispatch);
    },
    [mainState.allLibrary]
  );

  // Returns the next blob so the caller can save it in the same gesture —
  // reading state right after the dispatch would return the stale copy.
  const updateLibraryConditions = useCallback(
    (data) => libraryConditionsFn(mainState.allLibrary, data, dispatch),
    [mainState.allLibrary]
  );

  const updateActiveGsapGroupExtension = useCallback(
    (data) => {
      gsapGroupExtensionFn(mainState.allExtensions, data, dispatch);
    },
    [mainState.allExtensions]
  );

  const updateActiveGsapAllExtension = useCallback(
    (data) => {
      gsapAllExtensionFn(mainState.allExtensions, data, dispatch);
    },
    [mainState.allExtensions]
  );

  const updateActiveFullExtension = useCallback(
    (data) => {
      allExtensionFn(mainState.allExtensions, data, dispatch);
    },
    [mainState.allExtensions]
  );

  const updateNotice = useCallback(
    async (data) => {
      const result = mainState.notice;
      if (result.length >= 5) {
        result.pop();
      }
      result.unshift(data);

      await fetch(WCF_ADDONS_ADMIN.ajaxurl, {
        method: "POST",
        headers: {
          "Content-Type": "application/x-www-form-urlencoded",
          Accept: "application/json",
        },

        body: new URLSearchParams({
          action: "wcf_dashboard_notice_store",
          notice: JSON.stringify(result),
          nonce: WCF_ADDONS_ADMIN.nonce,
        }),
      })
        .then((response) => {
          return response.json();
        })
        .then((return_content) => {
          setNotice(result);
        });
    },
    [mainState.notice]
  );

  return {
    mainState,
    setAllWidgets,
    setAllAtomicWidgets,
    setAllExtensions,
    setAllAtomicExtensions,
    setActivated,
    setNotice,
    setTabKey,
    setIsSkipTerms,
    setSetupType,
    applyAtomicWidgetSetup,
    applyAtomicExtensionSetup,
    updateActiveWidget,
    updateActiveGroupWidget,
    updateActiveFullWidget,
    updateActiveAtomicWidget,
    updateActiveAtomicGroupWidget,
    updateActiveAtomicFullWidget,
    updateActiveAtomicExtension,
    updateActiveAtomicGroupExtension,
    updateActiveAtomicFullExtension,
    updateActiveGeneralExtension,
    updateActiveGeneralGroupExtension,
    updateActiveGsapExtension,
    updateLibrary,
    updateActiveGroupLibrary,
    updateLibraryConditions,
    updateActiveGsapGroupExtension,
    updateActiveGsapAllExtension,
    updateActiveFullExtension,
    updateNotice,
  };
};

export const AppContext = createContext({
  mainState: initialState,
  setAllWidgets: () => {},
  setAllExtensions: () => {},
  setActivated: () => {},
  setNotice: () => {},
  setTabKey: () => {},
  setIsSkipTerms: () => {},
  setSetupType: () => {},
  updateActiveWidget: () => {},
});

export const AppContextProvider = ({ children }) => {
  return (
    <AppContext.Provider value={useMainContext(initialState)}>
      {children}
    </AppContext.Provider>
  );
};
