import React from 'react';
import { init, AppProps } from '@hygraph/app-sdk';
import type {
  ExtensionDialogProps,
  FormSidebarExtensionProps,
} from '@hygraph/app-sdk';
import type { FieldExtensionProps } from './hooks';

type WrapperContext =
  | AppProps
  | FieldExtensionProps
  | FormSidebarExtensionProps
  | (ExtensionDialogProps & Record<string, unknown>);

type SDKState = 'init' | 'error' | 'ok' | 'validation';

const WrapperContext = React.createContext<WrapperContext>(
  {} as WrapperContext
);

type WrapperProps = {
  uid?: string;
  fallback?: React.FC<{ state: SDKState }>;
  debug?: boolean;
} & { children: React.ReactNode };

function useInitSDK<T>(uid?: string, debug: boolean = false) {
  const [sdkProps, setSdkProps] = React.useState<T>();
  const [extensionState, setExtensionState] = React.useState<SDKState>('init');

  React.useEffect(() => {
    async function initSdk() {
      try {
        const initialState = await init({
          uid,
          debug,
          onProps: setSdkProps,
        });
        if (initialState.status === 'ok') {
          setSdkProps(initialState.props);
        }
        setExtensionState(initialState.status);
      } catch (error) {
        setExtensionState('error');
        console.error(error);
      }
    }

    initSdk();
  }, [uid, debug]);

  return { sdkProps, extensionState };
}

export function Wrapper(props: WrapperProps) {
  const {
    children,
    uid,
    fallback: FallbackComponent = DefaultFallbackComponent,
    debug,
  } = props;

  const { sdkProps, extensionState } = useInitSDK<WrapperContext>(uid, debug);

  if (extensionState != 'ok' || !sdkProps)
    return <FallbackComponent state={extensionState} />;

  return <WrapperContext.Provider value={sdkProps} children={children} />;
}

export function useWrapperContext() {
  return React.useContext(WrapperContext);
}

function DefaultFallbackComponent({ state }: { state: SDKState }) {
  return (
    <p>
      {state === 'error'
        ? 'SDK connection error, check logs'
        : 'Waiting for connection'}
    </p>
  );
}
