/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
import type { Cell } from '@antv/x6';
import { Alert, Form, Input, Modal } from 'antd';
import React, { useEffect, useState } from 'react';
import { useIntl } from 'umi';

import PluginDetail from '../Plugin/PluginDetail';
import { fetchList } from '../Plugin/service';
import FlowGraph from './components/FlowGraph';
import Toolbar from './components/Toolbar';
import {
  DEFAULT_CONDITION_PROPS,
  DEFAULT_PLUGIN_PROPS,
  DEFAULT_STENCIL_WIDTH,
  DEFAULT_TOOLBAR_HEIGHT,
  FlowGraphEvent,
} from './constants';
import styles from './style.less';

type Props = {
  chart: {
    cells: Cell.Properties[];
  };
  readonly?: boolean;
};

type PluginProps = {
  id: string;
  name: string;
  visible: boolean;
  data: any;
};

type ConditionProps = {
  id: string;
  visible: boolean;
  data: string;
};

const PluginFlow: React.FC<Props> = ({ chart, readonly = false }) => {
  const { formatMessage } = useIntl();

  // NOTE: To prevent from graph is not initialized
  const [isReady, setIsReady] = useState(false);
  const [plugins, setPlugins] = useState<PluginComponent.Meta[]>([]);

  const [pluginProps, setPluginProps] = useState<PluginProps>(DEFAULT_PLUGIN_PROPS);
  const [conditionProps, setConditionProps] = useState<ConditionProps>(DEFAULT_CONDITION_PROPS);

  const getContainerSize = () => {
    const leftSidebar = document.querySelector('aside.ant-layout-sider');
    const blankSpaceWidth = 24 * 4;

    const globalHeaderHeight = 48;
    const pageHeaderHeight = 72;
    const otherHeight = 191;

    const width =
      document.body.offsetWidth -
      (leftSidebar?.clientWidth || 0) -
      blankSpaceWidth -
      DEFAULT_STENCIL_WIDTH;
    const height = document.body.offsetHeight - globalHeaderHeight - pageHeaderHeight - otherHeight;

    return {
      width,
      height: height < 800 ? 800 : height,
    };
  };

  useEffect(() => {
    if (!plugins.length) {
      return;
    }

    const container = document.getElementById('container');
    if (!container) {
      return;
    }

    const siderbarCollapsedButton = document.querySelector('.ant-pro-sider-collapsed-button');

    const graph = FlowGraph.init(container, plugins, chart);
    (window as any).graph = FlowGraph;
    setIsReady(true);

    const stencilContainer = document.querySelector('#stencil') as HTMLElement;

    const handleResize = () => {
      const { width, height } = getContainerSize();
      graph.resize(width, height);

      stencilContainer.style.height = `${height + DEFAULT_TOOLBAR_HEIGHT}px`;
      stencilContainer.style.width = `${DEFAULT_STENCIL_WIDTH}px`;
    };

    const handleLeftSidebarResize = () => {
      setTimeout(() => {
        handleResize();
      }, 200);
    };

    handleResize();

    graph.on(FlowGraphEvent.PLUGIN_CHANGE, setPluginProps);
    graph.on(FlowGraphEvent.CONDITION_CHANGE, (props: ConditionProps) => {
      setConditionProps(props);
    });

    if (readonly) {
      graph.disableKeyboard();
    }

    window.addEventListener('resize', handleResize);
    siderbarCollapsedButton?.addEventListener('click', handleLeftSidebarResize);
    // eslint-disable-next-line
    return () => {
      window.removeEventListener('resize', handleResize);
      siderbarCollapsedButton?.removeEventListener('click', handleLeftSidebarResize);
    };
  }, [plugins]);

  useEffect(() => {
    fetchList().then(setPlugins);
  }, []);

  return (
    <React.Fragment>
      {readonly && (
        <Alert
          type="warning"
          message={formatMessage({ id: 'component.plugin-flow.text.preview.readonly' })}
          showIcon
          style={{ marginBottom: 20 }}
        />
      )}
      <div className={styles.container}>
        <div
          id="stencil"
          className={styles.stencil}
          style={readonly ? { width: 0, height: 0 } : {}}
        />
        <div className={styles.panel}>
          <div className={styles.toolbar}>{isReady && <Toolbar />}</div>
          <div id="container" className={styles.flow}></div>
        </div>
      </div>
      {pluginProps.visible && (
        <PluginDetail
          readonly={readonly}
          schemaType="route"
          name={pluginProps.name}
          visible={pluginProps.visible}
          pluginList={plugins}
          isEnabled
          initialData={{
            // NOTE: We use {PluginName: data} because initialData is all plugins' data
            [pluginProps.name]: pluginProps.data,
          }}
          onClose={() => {
            setPluginProps(DEFAULT_PLUGIN_PROPS);
          }}
          onChange={({ formData, monacoData, shouldDelete }) => {
            if (shouldDelete) {
              FlowGraph.graph.removeCell(pluginProps.id);
            } else {
              const disable = !formData.disable;
              FlowGraph.setData(pluginProps.id, { ...monacoData, disable });
            }
            setPluginProps(DEFAULT_PLUGIN_PROPS);
          }}
        />
      )}

      <Modal
        visible={conditionProps.visible}
        title={formatMessage({ id: 'component.plugin-flow.text.condition.required' })}
        onOk={() => {
          FlowGraph.setData(conditionProps.id, conditionProps.data);
          setConditionProps(DEFAULT_CONDITION_PROPS);
        }}
        onCancel={() => setConditionProps(DEFAULT_CONDITION_PROPS)}
        okText={formatMessage({ id: 'component.global.confirm' })}
        cancelText={formatMessage({ id: 'component.global.cancel' })}
        okButtonProps={{
          disabled: readonly,
        }}
      >
        <Form.Item
          label={formatMessage({ id: 'component.plugin-flow.text.condition' })}
          style={{ marginBottom: 0 }}
          tooltip={formatMessage({ id: 'component.plugin-flow.text.condition-rule.tooltip' })}
        >
          <Input
            value={conditionProps.data}
            disabled={readonly}
            placeholder={formatMessage({ id: 'component.plugin-flow.text.condition.placeholder' })}
            onChange={(e) => {
              setConditionProps({
                ...conditionProps,
                data: e.target.value,
              });
            }}
          />
        </Form.Item>
      </Modal>
    </React.Fragment>
  );
};

export default PluginFlow;
