import React from 'react';
import cx from 'classnames';
import TreeSelector from '../../components/Tree';
import {
  FormOptionsControl,
  OptionsControl,
  OptionsControlProps
} from './Options';
import { Spinner } from '../../components';
import { SchemaApi } from '../../Schema';
import { findDOMNode } from 'react-dom';
import { ScopedContext, IScopedContext } from '../../Scoped';

/**
 * Tree 下拉选择框。
 * 文档：https://baidu.gitee.io/amis/docs/components/form/tree
 */
export interface TreeControlSchema extends FormOptionsControl {
  type: 'input-tree';

  /**
   * 是否隐藏顶级
   */
  hideRoot?: boolean;

  /**
   * 顶级选项的名称
   */
  rootLabel?: string;

  /**
   * 顶级选项的值
   */
  rootValue?: any;

  /**
   * 显示图标
   */
  showIcon?: boolean;

  /**
   * 父子之间是否完全独立。
   */
  cascade?: boolean;

  /**
   * 选父级的时候是否把子节点的值也包含在内。
   */
  withChildren?: boolean;

  /**
   * 选父级的时候，是否只把子节点的值包含在内
   */
  onlyChildren?: boolean;
  /**
   * 单选时，只运行选择叶子节点
   */
  onlyLeaf?: boolean;
  /**
   * 顶级节点是否可以创建子节点
   */
  rootCreatable?: boolean;

  /**
   * 是否开启节点路径模式
   */
  enableNodePath?: boolean;

  /**
   * 开启节点路径模式后，节点路径的分隔符
   */
  pathSeparator?: string;

  /**
   * 是否显示展开线
   */
  showOutline?: boolean;

  deferApi?: SchemaApi;
  /**
   * 是否默认选中第一个
   */
  loadFirst?: boolean
}

export interface TreeProps
  extends OptionsControlProps,
  Omit<
    TreeControlSchema,
    | 'type'
    | 'options'
    | 'className'
    | 'inputClassName'
    | 'descriptionClassName'
  > {
  enableNodePath?: boolean;
  pathSeparator?: string;
  selfAdaption?: boolean;
}

interface TreeState {
  // Aug 保存tree的展开状态
  spread: object | undefined,
  height: any
}

export default class TreeControl extends React.Component<TreeProps, TreeState> {
  static defaultProps: Partial<TreeProps> = {
    placeholder: 'placeholder.noData',
    multiple: false,
    rootLabel: '顶级',
    rootValue: '',
    showIcon: true,
    enableNodePath: false,
    pathSeparator: '/'
  };

  constructor(props: TreeProps) {
    super(props)
    // Aug
    this.state = {
      spread: undefined,
      height: document?.querySelector(props.treeContainerClassName) ? this.calcTreeHeight(document?.querySelector(props.treeContainerClassName)) : 300
      // treeContainerClassName
    }
  }

  reload() {
    const reload = this.props.reloadOptions;
    reload && reload();
  }

  // Aug
  handleKeepSqread(spread: object) {
    this.setState({ spread })
  }

  /**
    * @author:Chencicsy
    * @description:控制input-tree高度根据treeControl自适应
    * @param:selfAdaption
  **/

  calcTreeHeight = (dom?: any) => {
    const { classPrefix: ns } = this.props;
    if (!dom) {
      dom = findDOMNode(this)
    }

    // 获取treeControl的父节点
    let _parentDom = dom?.parentElement;

    // 获取form下的所有formItem
    let _silingDom = _parentDom?.parentElement?.children;

    let _bodyDom = _parentDom?.parentElement?.parentElement?.parentElement;
    // 要是form设置头部需要减去form的头部高度
    const headingHeight = document.querySelector("." + cx(`${ns}Panel-heading`))?.clientHeight as any

    // 获取页面的高度
    let _treeHeight: any = document.querySelector('.ant-tabs-content')?.clientHeight as any - 16 - 20 - (document.querySelector('.ant-tabs-content')?.querySelector('.antd-Tabs-links') ? 32 : 0) - (headingHeight ? headingHeight : 0);
    if (this.props.inModal) {
      _treeHeight = document.querySelector('.ant-tabs-content')?.clientHeight as any - 16 - 20 - (headingHeight ? headingHeight : 0) - (_parentDom?.parentElement as HTMLDivElement)?.getBoundingClientRect()?.top;
    }
    // 计算formItem的兄弟节点占据的高度
    [].slice.call(_silingDom).forEach((_ele: any) => {
      if (_ele !== _parentDom) {
        const _eleCss = window.getComputedStyle(_ele);
        const _eleHeight = _ele?.clientHeight + (+_eleCss.marginTop.replace('px', '')) + (+_eleCss.marginBottom.replace('px', ''))
        _treeHeight -= _eleHeight
      }
    });

    // 计算treeControl的兄弟节点占据的高度
    [].slice.call(_parentDom?.children).forEach((_ele: any) => {
      const _eleCss = window.getComputedStyle(_ele);
      if (_ele === dom) {
        _treeHeight -= ((+_eleCss.paddingTop.replace('px', '')) + (+_eleCss.paddingBottom.replace('px', '')))
      } else {
        const _eleHeight = _ele?.clientHeight + (+_eleCss.marginTop.replace('px', '')) + (+_eleCss.marginBottom.replace('px', ''))
        _treeHeight -= _eleHeight
      }
    })
    this.setState({
      height: _treeHeight
    })

  }

  MonitorFormResize = (e: any) => {
    this.calcTreeHeight()
  }

  componentDidMount() {
    this.calcTreeHeight()
    window.addEventListener('resize', this.MonitorFormResize);
  }

  componentWillUnmount() {
    window.removeEventListener('resize', this.MonitorFormResize);
  }

  // Aug 发送target数据
  handleChange(value: any, node: any) {
    const { onChange, name } = this.props
    let result = false
    if (node && node.target) {
      const scoped = this.context as IScopedContext;
      result = scoped.send(node.target, value, name);
    }
    onChange && onChange(value)
    return result
  }

  render() {
    const {
      className,
      treeContainerClassName,
      classPrefix: ns,
      value,
      enableNodePath,
      pathSeparator = '/',
      onChange,
      disabled,
      joinValues,
      extractValue,
      delimiter,
      placeholder,
      options,
      multiple,
      valueField,
      initiallyOpen,
      unfoldedLevel,
      withChildren,
      onlyChildren,
      onlyLeaf,
      loading,
      hideRoot,
      rootLabel,
      cascade,
      rootValue,
      showIcon,
      showRadio,
      showOutline,
      onAdd,
      creatable,
      createTip,
      addControls,
      onEdit,
      editable,
      editTip,
      editControls,
      removable,
      removeTip,
      onDelete,
      rootCreatable,
      rootCreateTip,
      labelField,
      iconField,
      nodePath,
      deferLoad,
      expandTreeOptions,
      translate: __,
      selfAdaption,
      loadFirst
    } = this.props;

    return (
      <div
        style={{
          height: this.state.height,
          [selfAdaption ? 'maxHeight' : '']: 'unset'
        }}
        className={cx(`${ns}TreeControl`, className, treeContainerClassName)}
      >
        <Spinner size="sm" key="info" show={loading} />
        {loading ? null : (
          <TreeSelector
            classPrefix={ns}
            loadFirst={loadFirst}
            labelField={labelField}
            valueField={valueField}
            iconField={iconField}
            disabled={disabled}
            // onChange={onChange}
            onChange={this.handleChange.bind(this)} // Aug
            joinValues={joinValues}
            extractValue={extractValue}
            delimiter={delimiter}
            placeholder={__(placeholder)}
            options={options}
            multiple={multiple}
            initiallyOpen={initiallyOpen}
            unfoldedLevel={unfoldedLevel}
            withChildren={withChildren}
            onlyChildren={onlyChildren}
            onlyLeaf={onlyLeaf}
            hideRoot={hideRoot}
            rootLabel={__(rootLabel)}
            rootValue={rootValue}
            showIcon={showIcon}
            showRadio={showRadio}
            showOutline={showOutline}
            cascade={cascade}
            foldedField="collapsed"
            value={value || ''}
            nodePath={nodePath}
            enableNodePath={enableNodePath}
            pathSeparator={pathSeparator}
            selfDisabledAffectChildren={false}
            onAdd={onAdd}
            creatable={creatable}
            createTip={createTip}
            rootCreatable={rootCreatable}
            rootCreateTip={rootCreateTip}
            onEdit={onEdit}
            editable={editable}
            editTip={editTip}
            removable={removable}
            removeTip={removeTip}
            onDelete={onDelete}
            bultinCUD={!addControls && !editControls}
            onDeferLoad={deferLoad}
            onExpandTree={expandTreeOptions}

            // Aug
            onKeepSqread={this.handleKeepSqread.bind(this)}
            spread={this.state.spread}
          />
        )}
      </div>
    );
  }
}

@OptionsControl({
  type: 'input-tree'
})
export class TreeControlRenderer extends TreeControl {

  // Aug -- 注册scoped对象
  static contextType = ScopedContext;

  constructor(props: TreeProps, context: IScopedContext) {
    super(props);

    const scoped = context;
    scoped.registerComponent(this);
  }

  componentWillMount() {
    const scoped = this.context;
    scoped.registerComponent(this);
  }

  componentWillUnmount() {
    const scoped = this.context;
    scoped.unRegisterComponent(this);
    super.componentWillUnmount()
  }
}
