import { useMemoizedFn, useAsyncEffect } from 'ahooks';
import { createContext, use, useState } from 'react';
import type { Blocklet } from '../type';
import { getBlockletData, getFederatedEnabled, getMaster } from '../Util/federated';

const BlockletContext = createContext<{
  blocklet: Blocklet | null;
  masterBlocklet: Blocklet | null;
}>({
  blocklet: null,
  masterBlocklet: null,
});

const { Provider, Consumer } = BlockletContext;

function BlockletProvider({
  children,
  baseUrl = '',
  loading = null,
}: {
  children: React.ReactNode;
  /**
   * baseUrl 为 blocklet origin + blocklet prefix
   */
  baseUrl?: string;
  loading?: React.ReactNode;
}) {
  const [blockletData, setBlockletData] = useState<Blocklet | null>(null);
  const [masterBlockletData, setMasterBlockletData] = useState<Blocklet | null>(null);
  const getBlockleDataWithCache = useMemoizedFn(async () => {
    if (!baseUrl || window.location.href.startsWith(baseUrl)) {
      throw new Error('no blocklet data');
    }
    const jsonData = await getBlockletData(baseUrl);
    return jsonData;
  });

  useAsyncEffect(async () => {
    let result = null;
    let resultMaster = null;
    try {
      result = await getBlockleDataWithCache();
    } catch {
      // NOTICE: 如果获取指定 blockletData 失败，则使用 window.blocklet
      const data = globalThis.blocklet || globalThis.env;
      result = data;
    }
    if (result) {
      if (getFederatedEnabled(result)) {
        const masterSite = getMaster(result);
        if (masterSite) {
          resultMaster = await getBlockletData(masterSite.appUrl);
        }
      }
    }
    setBlockletData(result);
    setMasterBlockletData(resultMaster);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [baseUrl]);
  return (
    <Provider value={{ blocklet: blockletData, masterBlocklet: masterBlockletData }}>
      {blockletData ? children : loading || null}
    </Provider>
  );
}

function useBlockletContext() {
  const { blocklet, masterBlocklet } = use(BlockletContext);
  return { blocklet, masterBlocklet };
}

export { BlockletContext, BlockletProvider, Consumer as BlockletConsumer, useBlockletContext };
