import { BLOCKLET_SERVICE_PATH_PREFIX } from '@arcblock/ux/lib/Util/constant';
import { useEffect, useRef, useState } from 'react';
import { joinURL } from 'ufo';

function parseUrl(uri: string, params: Record<string, any>): string {
  const url = new URL(uri);
  Object.keys(params).forEach((key) => {
    const value = params[key];
    if (value !== undefined) {
      url.searchParams.set(key, typeof value === 'string' ? value : JSON.stringify(value));
    }
  });
  return url.pathname + url.search;
}

interface BlockletStudioProps {
  open: boolean;
  setOpen: (open: boolean) => void;
  onOpened?: () => void;
  componentDid: string;
  tenantScope?: string;
  resourcesParams?: Record<string, any>;
  mode?: string;
  title?: string;
  logo?: string;
  description?: string;
  introduction?: string;
  note?: string;
  onUploaded?: (data: unknown) => void; // 上传后的回调函数
  onReleased?: (data: unknown) => void; // 发布一个新 release 后的回调函数
  onConnected?: (data: unknown) => void; // 连接后的回调函数
  components?: Record<string, unknown>[]; // 默认组件列表
  resources?: Record<string, unknown>; // 默认资源
  componentsTitle?: string;
  resourcesTitle?: string;
  style?: React.CSSProperties;
  zIndex?: number;
  dependentComponentsMode?: 'auto' | 'readonly'; // 禁用选择组件
  [key: string]: any;
}

function BlockletStudio({
  open,
  setOpen,
  onOpened = undefined,
  componentDid,
  tenantScope = undefined,
  resourcesParams = {},
  mode = 'dialog',
  title = undefined,
  logo = undefined,
  description = undefined,
  introduction = undefined,
  note = undefined,
  componentsTitle = undefined,
  resourcesTitle = undefined,
  onUploaded = undefined,
  onReleased = undefined,
  onConnected = undefined,
  components = [],
  resources = {},
  style = {},
  zIndex = 9999,
  dependentComponentsMode = undefined,
  ...rest
}: BlockletStudioProps) {
  const [opened, setOpened] = useState(false);
  const didRef = useRef('');
  didRef.current = componentDid;
  const latestFunctionVersionRef = useRef<{ [key: string]: undefined | ((data: unknown) => void) }>({});
  latestFunctionVersionRef.current['resourceDialog.close'] = () => {
    setOpened(false);
    setOpen(false);
  };
  latestFunctionVersionRef.current['resourceDialog.loaded'] = () => {
    setOpened(true);
    onOpened?.();
  };
  latestFunctionVersionRef.current['studioDialog.uploaded'] = onUploaded;
  latestFunctionVersionRef.current['studioDialog.connected'] = onConnected;
  latestFunctionVersionRef.current['studioDialog.released'] = onReleased;

  useEffect(() => {
    const listener = (event: MessageEvent) => {
      if (event?.data?.componentDid !== didRef.current) {
        return;
      }
      const fn = latestFunctionVersionRef.current[event?.data?.event];
      if (typeof fn === 'function') {
        fn(event?.data?.data);
      }
    };
    window.addEventListener('message', listener);
    return () => {
      window.removeEventListener('message', listener);
    };
  }, []);

  if (!open) {
    return null;
  }

  const src = parseUrl(
    joinURL(window.location.origin, BLOCKLET_SERVICE_PATH_PREFIX, '/embed/resources', componentDid, '/publish'),
    {
      title,
      logo,
      description,
      introduction,
      note,
      tenantScope,
      mode,
      resourcesParams,
      resources,
      components,
      resourcesTitle,
      componentsTitle,
      dependentComponentsMode,
    }
  );

  return (
    <iframe
      src={src}
      title="Blocklet Studio"
      style={{
        position: 'fixed',
        top: 0,
        left: 0,
        width: '100vw',
        height: '100vh',
        zIndex,
        border: 0,
        padding: 0,
        margin: 0,
        pointerEvents: opened ? 'auto' : 'none',
        opacity: opened ? 1 : 0,
        ...style,
      }}
      {...rest}
    />
  );
}

export default BlockletStudio;
