import React from 'react';
import { Renderer, RendererProps } from '../factory';
import { ResizeEvent, Schema } from '../types';
import pick from 'lodash/pick';
import {
  BaseSchema,
  SchemaClassName,
  SchemaCollection,
  SchemaObject
} from '../Schema';
import { FormSchemaHorizontal } from './Form/index';
import { domUtils, isMobile, ucFirst } from '../utils/helper';

import { Icon } from '../components/icons';
import { getStyleNumber } from '../utils/dom';
import { CaretLeftOutlined, CaretRightOutlined, DoubleLeftOutlined, DoubleRightOutlined } from '@ant-design/icons';
export const ColProps = ['lg', 'md', 'sm', 'xs'];

export type GridColumnObject = {
  /**
   * 极小屏（<768px）时宽度占比
   */
  xs?: number | 'auto';

  /**
   * 小屏时（>=768px）宽度占比
   */
  sm?: number | 'auto';

  /**
   * 中屏时(>=992px)宽度占比
   */
  md?: number | 'auto';

  /**
   * 大屏时(>=1200px)宽度占比
   */
  lg?: number | 'auto';

  /**
   * 垂直对齐方式
   */
  valign?: 'top' | 'middle' | 'bottom' | 'between';

  /**
   * 配置子表单项默认的展示方式。
   */
  mode?: 'normal' | 'inline' | 'horizontal';

  /**
   * 如果是水平排版，这个属性可以细化水平排版的左右宽度占比。
   */
  horizontal?: FormSchemaHorizontal;

  body?: SchemaCollection;

  // 占据的行数
  rowKey?: number
  // 总行数
  rowCount?: number
  // 是否固定高度
  fixedHeight?: boolean

  /**
   * 列类名
   */
  columnClassName?: SchemaClassName;
  // Jay
  style: {
    [key: string]: string | number;
  }
  /**
   * 特殊处理移动端需要水平布局的情况
   */
  mobLayout?: boolean
};

export type GridColumn = GridColumnObject;
export type ColumnNode = GridColumn;
export interface ColumnArray extends Array<ColumnNode> { }

/**
 * Grid 格子布局渲染器。
 * 文档：https://baidu.gitee.io/amis/docs/components/grid
 */
export interface GridSchema extends BaseSchema {
  /**
   * 指定为 Grid 格子布局渲染器。
   */
  type: 'grid';

  /**
   * 列集合
   */
  columns: Array<GridColumn>;

  /**
   * 水平间距
   */
  gap?: 'xs' | 'sm' | 'base' | 'none' | 'md' | 'lg';

  /**
   * 垂直对齐方式
   */
  valign?: 'top' | 'middle' | 'bottom' | 'between';

  /**
   * 水平对齐方式
   */
  align?: 'left' | 'right' | 'between' | 'center';

  /**
   * 是否可拖动
   */
  scroll?: boolean
  /**
  * 是否上下展示
  */
  distance?: boolean
}

export interface GridProps
  extends RendererProps,
  Omit<GridSchema, 'type' | 'className' | 'columnClassName'> {
  itemRender?: (item: any, length: number, props: any) => JSX.Element;
  sroll?: boolean;
  className?: string;
  distance?: boolean;
}

function fromBsClass(cn: string) {
  if (typeof cn === 'string' && cn) {
    return cn.replace(
      /\bcol-(xs|sm|md|lg)-(\d+)\b/g,
      (_, bp, size) => `Grid-col--${bp}${size}`
    );
  }

  return cn;
}

function copProps2Class(props: any): string {
  const cns: Array<string> = [];
  const modifiers = ColProps;

  modifiers.forEach(
    modifier =>
      props &&
      props[modifier] &&
      cns.push(`Grid-col--${modifier}${ucFirst(props[modifier])}`)
  );
  cns.length || cns.push('Grid-col--md');
  return cns.join(' ');
}

export default class Grid<T> extends React.Component<GridProps & T, {
  x: number,
  scrollRefLeft: number,
  scrollRefTop: number,
  mds: string[],
  isDrag: boolean,
  distanceStyle: string,
  navVisible: boolean,
  // isHovered: boolean,
  // showLeft?: boolean
}> {
  static propsList: Array<string> = ['columns'];

  // static defaultProps = {
  //   scroll: true
  // }
  showCollpase: boolean
  pageContentId: string = '';
  scrollParent: any = React.createRef()
  scrollRef: any = React.createRef()
  scrollRefChildren: any = React.createRef()
  gridRef: any = React.createRef();
  
  constructor(props: GridProps & T) {
    super(props);
    this.state = {
      x: 0,
      scrollRefLeft: 0,
      scrollRefTop: 0,
      mds: [],
      isDrag: false,
      distanceStyle: "unset",
      navVisible: true,
      // isHovered: false
    }
    // this.showCollpase = !!props.scroll && !(isMobile() || props.distance)
    this.scrollRefMouseDown = this.scrollRefMouseDown.bind(this)
    this.scrollRefMouseUp = this.scrollRefMouseUp.bind(this)
    this.scrollRefMouseUps = this.scrollRefMouseUps.bind(this)
    this.antiShake = this.antiShake.bind(this)
    this.updateAutoFillHeight = this.updateAutoFillHeight.bind(this);
  }


  timer: any = null;
  timmerHandle: any = null;
  get region() {
    let total = 0;
    let regions: number[] = [];
    this.props.columns.forEach(column => {
      total += (+column?.md! ?? 0);
      column?.md && regions.push(+column?.md!)
    })
    return {
      total,
      regions
    }
  }

  antiShake(callBack: Function, wait = 1000, rest?: unknown) {
    let that = this;
    return () => {
      if (that.timer) {
        clearTimeout(that.timer);
        that.timer = null;
      }
      that.timer = setTimeout(() => {
        callBack(rest)
      }, wait)
    }
  }



  renderChild(
    region: string,
    node: SchemaCollection,
    length: number,
    props: any = {}
  ) {
    const { render, itemRender } = this.props;

    return itemRender
      ? itemRender(node, length, this.props)
      : render(region, node, props);
  }

  scrollRefMouseDown(e: MouseEvent) {
    if (this.region.regions?.length > 2) return;
    let initregion: number = this.region.regions[0] / this.region.total / 2;
    if (e.target === this.scrollRefChildren.current) {
      this.timmerHandle = setTimeout(() => {
        this.setState({ isDrag: true })
        this.gridRef.current.onmousemove = (mouse: any) => {
          window.getSelection()?.removeAllRanges()
          let x = mouse.clientX;
          let y = mouse.clientY;
          let mds: string[] = [];
          let leftRegion: number = (x - e.clientX + this.state.scrollRefLeft) / this.gridRef.current?.clientWidth;
          let topRegion: number = (y - e.clientY + this.state.scrollRefTop) / this.gridRef.current?.clientHeight;
          if (this.props?.distance) {
            // 控制可以下拉多大，占据屏幕多大，1为100%
            if (topRegion >= 0.95 || topRegion <= initregion) return;
            mds.push(topRegion * 100 + '%');
            // 控制从表最小多少
            // (topRegion * 100 <= 50) ?
            mds.push((1 - topRegion) * 100 + '%')
            // :
            // mds.push(50 + '%');
          } else {
            if (leftRegion >= 0.5 || leftRegion <= initregion) return;
            mds.push(leftRegion * 100 + '%')
            mds.push((1 - leftRegion) * 100 + '%')
          }
          this.setState({ mds: mds })
        }
      }, 150)
    }
  }

  // 鼠标左键抬起时清除拖动事件，并且将滑块当前位置进行记录
  scrollRefMouseUp(e: MouseEvent) {
    if (this.props.scroll) {

      if (!this.state.isDrag && !this.props?.distance && e.target === this.scrollRefChildren.current) {
        this.gridRef.current.onmousemove = "";
        // if (this.state.scrollRefLeft > 20) {
        //   this.setState({
        //     scrollRefLeft: 0,
        //     mds: ["0.1%", "calc(99% - 20px)"]
        //   });
        // } else {
        //   this.setState({
        //     scrollRefLeft: 160,
        //     mds: ["16.6667%", "83.3333%"]
        //   });
        // }
      } else {
        document.body.dispatchEvent(new Event(ResizeEvent.DRAGCONTENTRESIZE, { bubbles: true }))
        if (this.props?.distance) {
          this.setState({
            scrollRefTop: this.scrollRef.current.offsetTop,
            isDrag: false
          })
        } else {
          this.setState({
            scrollRefLeft: this.scrollRef.current.offsetLeft,
            isDrag: false
          })
        }
      }
      this.gridRef.current.onmousemove = "";
    }

    clearTimeout(this.timmerHandle);

  }
  handleClickCollpase = () => {
    const { navVisible } = this.state;
    if (navVisible) {
      this.setState({
        navVisible: !navVisible,
        scrollRefLeft: 0,
        mds: ["0.1%", "calc(99.9% - 12px)"]
      })
    } else {
      this.setState({
        navVisible: !navVisible,
        scrollRefLeft: 160,
        mds: ["16.6667%", "83.3333%"]
      });
    }
  }
  // 全局鼠标左键抬起时清除拖动事件
  scrollRefMouseUps(e: MouseEvent) {
    this.gridRef.current.onmousemove = () => { };
  }

  // renderLine() {
  //   const { classnames: cx } = this.props;
  //   return (
  //     <div className={cx('Grid-line')} ref={this.scrollRef} >
  //       <div className={'collpase'}
  //         ref={this.scrollRefChildren}
  //         onMouseEnter={() => this.setState({ isHovered: true })}
  //         onMouseLeave={() => {
  //           if (!this.state.isDrag) {
  //             this.setState({ isHovered: false })
  //           }
  //         }}
  //       >
  //         {(this.state.showLeft === undefined || this.state.showLeft === true) && (
  //           <CaretLeftOutlined
  //             className={`left ${this.state.isHovered ? 'left-hovered' : ''}`}
  //             onClick={(e) => {
  //               e.stopPropagation()
  //               if (this.state.showLeft == undefined) {
  //                 this.setState({ showLeft: false })
  //               } else {
  //                 this.setState({ showLeft: undefined, scrollRefLeft: 21 })
  //               }
  //             }}
  //           />
  //         )}
  //         {(this.state.showLeft === undefined || this.state.showLeft === false) && (
  //           <CaretRightOutlined
  //             className={`right ${this.state.isHovered ? 'right-hovered' : ''}`}
  //             onClick={(e) => {
  //               e.stopPropagation()
  //               if (this.state.showLeft == undefined) {
  //                 this.setState({ showLeft: true })
  //               } else {
  //                 this.setState({ showLeft: undefined, scrollRefLeft: 21 })
  //               }
  //               // 如果容器下有固定到右侧的弹窗容器，才进行操作
  //               const hasPinModal = domUtils.closest(this.gridRef.current as HTMLElement, `.main-page-content.${this.pageContentId}`)?.querySelector('.dialog-pin-right.dialog-fix-right');
  //               if (hasPinModal) {
  //                 const targetEvent = this.state.showLeft == undefined ? ResizeEvent.RESET_MAIN_PAGE_WIDTH + this.pageContentId : ResizeEvent.STOP_RESIZE_AFTER_PIN + this.pageContentId;
  //                 document.body.dispatchEvent(new Event(targetEvent));
  //               }
  //             }}
  //           />
  //         )}
  //       </div>
  //     </div>
  //   )
  // }

  renderColumn(column: ColumnNode, key: number, length: number) {
    let colProps: {
      [propName: string]: any;
    } = pick(column, ColProps);

    colProps = {
      ...colProps
    };

    const {
      classnames: cx,
      formMode,
      subFormMode,
      subFormHorizontal,
      formHorizontal,
      translate: __,
      scroll,
      className,
      distance,
      classPrefix: ns
    } = this.props;

    const {
      mds,
      scrollRefLeft
    } = this.state;

    let style: any = {}
    const statistics = (this.props?.columns?.[0]?.body as Array<any>)[0]?.body?.name

    // 如果高度固定了不设置高度 防止冲突
    if (column.fixedHeight)
      style.height = 'unset'
    if (scroll && this.region.regions?.length <= 2) {
      if (this.props?.distance) {
        style = mds?.length > 0 ? {
          flex: '0 0 ' + mds[key],
          maxHeight: mds[key],
          height: mds[key],
          maxWidth: + 100 + "%"
        } : {
          flex: '0 0 ' + 50 + "%",
          maxHeight: + 50 + "%",
          height: isMobile() ? '50%' : 'inherit'
        }
      } else {
        style = mds?.length > 0 ? {
          flex: '0 0 ' + mds[key],
          maxWidth: mds[key],
          minWidth: '12px',
        } : {
          flex: '0 0 ' + (this.region.regions[key] / this.region.total * 100 + '%'),
          maxWidth: (this.region.regions[key] / this.region.total * 100 + '%')
        }
      }
    }

    if (key === 0 && scroll) {
      return (
        <>
          <div
            key={key}
            style={{
              ...style,
              position: 'relative',
              height: !isMobile() && scroll && !distance && this.gridRef.current?.closest(`.${ns}Modal`) ? 'unset' : '100%',
            }}
            ref={this.scrollParent}
            className={cx(
              copProps2Class(colProps),
              fromBsClass((column as any).columnClassName!),
              {
                [`Grid-col--v${ucFirst(column.valign)}`]: column.valign,
                'grid-item': className?.includes('grid-item'),
                'mobile-grid-item': isMobile(),
                'Grid-item--combination': !isMobile() && scroll && !distance && !className?.includes('Combination'),
                'scroll-grid-child-item': !isMobile() && scroll && !distance,
                'inline-grid-item': isMobile() && column.mobLayout
              }
            )}
          >
            {this.renderChild(`column/${key}`, (column as any).body || '', length, {
              formMode: column.mode || subFormMode || formMode,
              formHorizontal:
                column.horizontal || subFormHorizontal || formHorizontal,
              bodyName: statistics,
              // style: isMobile() && !distance ? { flex: 1 } : {}
            })}

            <span className={cx('Grid--slider', {
              'slider-closed': !this.state.navVisible
            })} ref={this.scrollRef} >
              {this.props?.distance ?
                <Icon icon="up-and-down-arrow" className="icon" /> : null
              }
              <div className={cx('Grid--sliders')} ref={this.scrollRefChildren}></div>
            </span>
            {isMobile() || distance ? null : <div onClick={(e) => {
              e.stopPropagation()
              this.handleClickCollpase()
            }} className={`grid-collpase ${this.state.navVisible ? '' : 'closed'}`}>
              {
                this.state.navVisible ? <span>
                  <DoubleLeftOutlined style={{ fontSize: '11px' }} />收缩
                </span> : <span>
                  <DoubleRightOutlined style={{ fontSize: '11px' }} />展开
                </span>
              }
            </div>}
          </div>
          {/* {this.showCollpase && this.renderLine()} */}
        </>
      )
    }

    return <div
      key={key}
      style={style}
      className={cx(
        copProps2Class(colProps),
        fromBsClass((column as any).columnClassName!),
        {
          [`Grid-col--v${ucFirst(column.valign)}`]: column.valign,
          'grid-item': className?.includes('grid-item'),
          'mobile-grid-item': isMobile(),
          'Grid-item--combination': !isMobile() && scroll && !distance && !className?.includes('Combination'),
          'scroll-grid-child-item': !isMobile() && scroll && !distance,
          'inline-grid-item': isMobile() && column.mobLayout
        }
      )}
    >
      {this.renderChild(`column/${key}`, (column as any).body || '', length, {
        formMode: column.mode || subFormMode || formMode,
        formHorizontal:
          column.horizontal || subFormHorizontal || formHorizontal,
        bodyName: statistics
      })}
    </div>
  }

  renderColumns(columns: ColumnArray) {

    // // 根据md分成的行分布数组
    // const mdMatrix = create2DArrayByMaxSum(this.props.columns.map(_ => +(_?.md || 12)), 12)
    // 计算对应md的行数
    // const IndexToRowKey = (() => {
    //   const result = {}
    //   mdMatrix.map((row, index) => row.map((columns: any, colIndex: any) => { result[index + colIndex] = index + 1 }))
    //   return result
    // })()
    return Array.isArray(columns)
      ? columns.map((column, key) =>
        this.renderColumn({
          ...column,
          // rowKey: IndexToRowKey[key], rowCount: mdMatrix.length, 
          fixedHeight: !!(column?.body as any[])?.find?.(_ => _.fixedHeight)
        }, key, columns.length)
      )
      : null;
  }

  componentDidMount() {
    const { scroll } = this.props;
    if (scroll) {
      this.setState({
        scrollRefLeft: this.scrollRef.current?.offsetLeft,
        scrollRefTop: this.scrollRef.current.offsetTop
      })
    }
    this.updateAutoFillHeight();
    this.gridRef.current.addEventListener('mousedown', this.scrollRefMouseDown);
    this.gridRef.current.addEventListener('mouseup', this.scrollRefMouseUp);
    document.addEventListener('mouseup', this.scrollRefMouseUps)
    window.addEventListener('resize', this.updateAutoFillHeight);
    // 用于解决AI助手固定右侧的时候显示异常
    const pageContentDom = domUtils.closest(this.gridRef.current as HTMLElement, '.main-page-content');
    const pageContentIdMatch = pageContentDom?.className.split(' ').find((item) => item.includes('page-content-id_')) ?? '';
    this.pageContentId = pageContentIdMatch;
  }

  componentWillUnmount() {
    this.gridRef.current.removeEventListener('mousedown', this.scrollRefMouseDown);
    this.gridRef.current.removeEventListener('mouseup', this.scrollRefMouseUp);
    document.removeEventListener('mouseup', this.scrollRefMouseUps)
    window.removeEventListener('resize', this.updateAutoFillHeight);
  }
  updateAutoFillHeight() {
    if (this.props.distance) {
      // 获取整个屏幕的高度
      const viewportHeight = isMobile() ? document.body.clientHeight : window.innerHeight;
      // 获取当前元素的头部位置
      const distanceTop = this.gridRef.current.getBoundingClientRect().top

      const formWizard = document.getElementById("form-wizard")?.parentElement as HTMLElement
      // 获取Model
      const Modal = document.getElementsByClassName("amis-dialog-widget")
      let parentNode = this.gridRef.current.parentElement;
      let footerHeight = 0
      let contentBottom = 0
      if (Modal) {
        for (let index = 0; index < Modal.length; index++) {
          if (Modal[index].contains(this.gridRef.current)) {
            Modal[index].childNodes.forEach((item: HTMLElement) => {
              if (item.className.includes("Modal-content")) {
                item.childNodes.forEach((i: HTMLElement) => {
                  if (i.className.includes("Modal-footer")) {
                    footerHeight = footerHeight + i.offsetHeight
                  }
                  if (i.className.includes("Modal-body")) {
                    // 循环获取在model中当前元素所有的祖先元素到Modal-body的内边距和底部border的宽度
                    while (parentNode !== i) {
                      const paddingButtom = getStyleNumber(parentNode, 'padding-bottom');
                      const borderBottom = getStyleNumber(parentNode, 'border-bottom-width');
                      contentBottom = contentBottom + paddingButtom + borderBottom
                      parentNode = parentNode.parentElement;
                    }
                  }
                })
              }
            })
          }
        }
      }
      if (formWizard && formWizard.contains(this.gridRef.current)) {
        formWizard.childNodes.forEach((m: HTMLElement) => {
          if (m.className.includes("Wizard-footer")) {
            footerHeight = +  m.offsetHeight
          }
        })
      }
      // 循环计算父级节点的 pddding，这里不考虑父级节点还可能会有其它兄弟节点的情况了
      let allParentPaddingButtom = 0;
      while (parentNode) {
        const paddingButtom = getStyleNumber(parentNode, 'padding-bottom');
        const borderBottom = getStyleNumber(parentNode, 'border-bottom-width');
        allParentPaddingButtom =
          allParentPaddingButtom + paddingButtom + borderBottom;
        parentNode = parentNode.parentElement;
      }
      const finalHeight = viewportHeight - distanceTop - footerHeight - contentBottom - parentNode
      if (finalHeight > 700) {
        this.setState({
          distanceStyle: finalHeight + "px"
        })
      } else {
        this.setState({
          distanceStyle: (document.body.clientHeight - 38) + 'px'
        })
      }
    }
  }



  render() {

    const {
      className,
      classnames: cx,
      gap,
      valign: vAlign,
      align: hAlign,
      distance,
      scroll,
      style,
      fullScreen
    } = this.props;
    const { distanceStyle, scrollRefLeft } = this.state;
    // 顶级的得让他滚动
    // const isTopGrid = this.gridRef?.current?.parentElement?.className?.include?.('Page-body')
    // console.log(isTopGrid)
    return (
      <div
        ref={this.gridRef}
        className={cx(
          'Grid',
          {
            [`Grid--${gap}`]: gap,
            [`Grid--v${ucFirst(vAlign)}`]: vAlign,
            [`Grid--h${ucFirst(hAlign)}`]: hAlign,
            'Distance': distance,
            'Grid--combination': !isMobile() && scroll && !distance && !className?.includes('Combination'),
            'Grid-item-search': scrollRefLeft > 20 ? false : true,
            'scroll-grid-item': !isMobile() && scroll && !distance
          },
          className
        )}
        // Jay
        style={{ ...style, maxHeight: distanceStyle, height: distanceStyle, overflow: '' }}
      >
        {this.renderColumns(this.props.columns)}
      </div>
    );
  }
}

@Renderer({
  type: 'grid'
})
export class GridRenderer extends Grid<{}> { }
