import { BLOCKLET_SERVICE_PATH_PREFIX } from '@arcblock/did-connect-react/lib/constant';
import { useEffect, useMemo, useRef, useState } from 'react';
import { joinURL } from 'ufo';

const parseDidToSet = (did) => {
  if (typeof did === 'string') {
    return new Set(did.split(';;'));
  }
  return new Set(did);
};

function useComponentInstalled({ did, onInstalled, onError }) {
  const didKeys = Array.isArray(did) ? did.join(';;') : did;
  const [installStatus, setInstallStatus] = useState({});
  const onInstalledRef = useRef({ onInstalled, onError });
  onInstalledRef.current = { onInstalled, onError };

  const { optionalComponents, componentMountPoints } = window.blocklet;

  const optComponents = useMemo(() => {
    if (!optionalComponents || !optionalComponents.length) {
      return [];
    }
    const didSet = parseDidToSet(didKeys);
    const components = optionalComponents.filter((c) => didSet.has(c.meta.did));
    (components ? onInstalledRef.current.onError : onInstalledRef.current.onInstalled)?.(components);
    return components;
  }, [didKeys, optionalComponents]);

  const definedInBlockletYML = useMemo(() => {
    if (optComponents.length) {
      return true;
    }
    const didSet = parseDidToSet(didKeys);
    return (componentMountPoints || []).find((item) => didSet.has(item.did));
  }, [optComponents, componentMountPoints, didKeys]);

  optComponents.forEach((item) => {
    item.storeUrl = joinURL(item.meta.homepage, 'blocklets', item.meta.did);
    item.installUrl = joinURL(
      window.blocklet.appUrl,
      BLOCKLET_SERVICE_PATH_PREFIX,
      `/admin/components?install-component=${item.meta.did}`
    );
  });

  useEffect(() => {
    const handle = (event) => {
      if (event.origin !== window.blocklet.appUrl) {
        return;
      }

      if (event.data?.kind === 'component-installer' && event.data?.blocklet?.children) {
        let hasChild = false;
        const didSet = parseDidToSet(didKeys);
        event.data?.blocklet?.children.forEach((item) => {
          if (didSet.has(item.meta?.did)) {
            hasChild = true;
            setInstallStatus((value) => {
              return {
                ...value,
                [item.meta?.did]: item.status || 'waiting',
              };
            });
          }
        });
        if (!hasChild) {
          setInstallStatus({});
        }
      }
    };

    window.addEventListener('message', handle);
    return () => {
      window.removeEventListener('message', handle);
    };
  }, [didKeys]);

  return {
    optComponents,
    installed: !optComponents.length && definedInBlockletYML,
    installStatus,
    setInstallStatus,
    definedInBlockletYML,
  };
}

export default useComponentInstalled;
