import React, { useEffect, useMemo, useRef, useState } from 'react';
import Sortable from 'sortablejs';
import cloneDeep from 'lodash/cloneDeep';
import { RendererProps } from '../../factory';
import Overlay from '../../components/Overlay';
import PopOver from '../../components/PopOver';
import Modal from '../../components/Modal';
import Button from '../../components/Button';
import Checkbox from '../../components/Checkbox';
import TooltipWrapper from '../../components/TooltipWrapper';
import type { TooltipObject } from '../../components/TooltipWrapper';
import { noop, uuid } from '../../utils/helper';
import { filter } from '../../utils/tpl';
import { Icon } from '../../components/icons';
import { RootClose } from '../../utils/RootClose';
import { IColumn } from '../../store/table';
import { CloseCircleOutlined, DeleteOutlined, EditOutlined, PushpinOutlined, VerticalAlignTopOutlined } from '@ant-design/icons';
import { normalizeApi } from '../../utils/api';
import { Form, Input, Modal as TemplateModal, Popconfirm, Select, message } from 'antd';
// Jay

export interface ColumnTogglerProps extends RendererProps {
  /**
   * 按钮文字
   */
  label?: string | React.ReactNode;

  /**
   * 按钮提示文字，hover focus 时显示
   */
  tooltip?: string | TooltipObject;

  /**
   * 禁用状态下的提示
   */
  disabledTip?: string | TooltipObject;

  /**
   * 点击外部是否关闭
   */
  closeOnOutside?: boolean;

  /**
   * 点击内容是否关闭
   */
  closeOnClick?: boolean;

  /**
   * 下拉菜单对齐方式
   */
  align?: 'left' | 'right';

  /**
   *  ColumnToggler的CSS类名
   */
  className?: string;

  /**
   * 按钮的CSS类名
   */
  btnClassName?: string;

  /**
   * 按钮大小
   */
  size?: 'xs' | 'sm' | 'md' | 'lg';

  /**
   * 按钮级别，样式
   */
  level?: 'info' | 'success' | 'danger' | 'warning' | 'primary' | 'link';

  /**
   * 是否独占一行 `display: block`
   */
  block?: boolean;

  /**
   * 是否可通过拖拽排序
   */
  draggable?: boolean;

  /**
   * 默认是否展开
   */
  defaultIsOpened?: boolean;

  /**
   * 激活状态
   */
  isActived?: boolean;

  /**
   * ICON名称
   */
  icon?: string | React.ReactNode;

  /**
   * 是否只显示图标。
   */
  iconOnly?: boolean;

  /**
   * 是否隐藏展开的Icon
   */
  hideExpandIcon?: boolean;

  /**
   * 是否显示遮罩层
   */
  overlay?: boolean;

  /**
   * 列数据
   */
  columns: Array<IColumn>;
  // Jay
  getRawColumns?: () => Array<IColumn>; // 未进行显隐和排序处理的列数据
  onColumnToggle: (columns: Array<IColumn> | undefined, saveCols: Record<string, any>, canFetch: boolean, targetTemp?: Temp) => void;
  modalContainer?: () => HTMLElement;
  filteredColumns?: Array<IColumn>;
  saveColApi?: {
    data?: { [key: string]: string },
    method: 'string',
    url: string
  }
}

type SaveColType = Record<string, { index: number, hidden: 0 | 1, fixed?: string }>

export interface Temp {
  tempKey: string;
  tempName: string;
  columnInfo: SaveColType;
}

const ColumnToggler = (props: ColumnTogglerProps) => {
  const { tooltip, placement, tooltipContainer, tooltipTrigger, tooltipRootClose, disabledTip, block, disabled, btnDisabled, $schema,
    btnClassName, size, label, level, primary, className, classnames: cx, align, iconOnly, icon, isActived, data, draggable,
    classPrefix: ns, modalContainer, overlay, defaultIsOpened, columns, saveColApi, env, hideExpandIco, render, translate: __ } = props;
  const [isOpened, setIsOpend] = useState(defaultIsOpened);
  const [tempColumns, setTempColumns] = useState<IColumn[]>([]);
  const [sortColumns, setSortColumns] = useState<IColumn[]>([]);
  const [tempList, setTempList] = useState<Temp[]>([]);
  const [tempVisible, setTempVisible] = useState(false);
  const [selectedTemp, setSelectedTemp] = useState('');
  const [editingTemp, setEditingTemp] = useState('');
  const [form] = Form.useForm();
  const target = useRef<HTMLDivElement>();
  const sortable = useRef<Sortable>();
  const dialogRef = useRef<any>(undefined);
  const sortColumnsRef = useRef<IColumn[]>([]);
  const domRef = (ref: any) => {
    target.current = ref;
  }

  const selectAll = useMemo(() => {
    return tempColumns.filter(item => item.toggled).length === tempColumns.length
  }, [tempColumns])

  const initColumns = (cols: IColumn[]) => {
    const colList = cloneDeep(cols).filter(item => item.type !== 'operation')
    setTempColumns(colList)
    setSortColumns(colList)
  }

  useEffect(() => {
    if (isOpened) {
      initColumns(columns)
      getTempList()
    }
  }, [columns, isOpened])

  useEffect(() => {
    sortColumnsRef.current = sortColumns
  }, [sortColumns])

  useEffect(() => {
    initDragging();
    return () => {
      destroyDragging()
      target.current = undefined
    }
  }, [])

  //获取模板列表并保存
  const getTempList = async () => {
    const api = normalizeApi(saveColApi?.url || '', 'get')
    const { data } = await env.fetcher(api)
    setTempList(data?.filter((item: Temp) => item.tempKey) || [])
  }

  const destroyDragging = () => {
    sortable.current && sortable.current.destroy();
  }

  // @autobind
  const dragRef = (ref: any) => {
    if (draggable && ref) {
      initDragging();
    }
  }
  let canConfirmFetch = false;
  const toggle = (e: React.MouseEvent<any>) => {
    e.preventDefault();
    setIsOpend(!isOpened)
  }

  const updateToggledColumn = (
    column: IColumn,
    index: number,
    value: any,
    shift?: boolean
  ) => {
    const newtempColumns = tempColumns.concat();
    const targetColumn = {
      ...column,
      // Jay
      pristine: { ...column?.pristine, hidden: !value },
      toggled: value
    }
    newtempColumns.splice(index, 1, targetColumn);
    canConfirmFetch = true
    setTempColumns(newtempColumns)
    let newSortColumns = [...sortColumns]
    const target = newSortColumns.findIndex(item => item.name === column.name)
    if (value) {
      newSortColumns.splice(target, 1)
      newSortColumns.push(targetColumn)
    } else {
      newSortColumns.splice(target, 1, targetColumn)
    }
    setSortColumns(newSortColumns)
  }
  const button = (
    <button
      onClick={toggle}
      disabled={disabled}
      className={cx(
        'Button',
        btnClassName,
        typeof level === 'undefined'
          ? 'Button--default'
          : level
            ? `Button--${level}`
            : '',
        {
          'Button--block': block,
          'Button--primary': primary,
          'Button--iconOnly': iconOnly
        },
        size ? `Button--${size}` : ''
      )}
    >
      {icon ? (
        typeof icon === 'string' ? (
          <i className={cx(icon, 'm-r-xs')} />
        ) : (
          icon
        )
      ) : null}
      {typeof label === 'string' ? filter(label, data) : label}
      {hideExpandIco || draggable ? null : (
        <span className={cx('ColumnToggler-caret')}>
          <Icon icon="caret" className="icon" />
        </span>
      )}
    </button>
  )

  const swapColumnPosition = (oldIndex: number, newIndex: number) => {
    const newColumns = [...sortColumnsRef.current]
    const oldColumn = newColumns[oldIndex]
    newColumns.splice(newIndex > oldIndex ? newIndex + 1 : newIndex, 0, oldColumn)
    oldIndex > newIndex ? newColumns.splice(oldIndex + 1, 1) : newColumns.splice(oldIndex, 1)
    setSortColumns(newColumns)
  }

  const renderOuter = () => {
    const {
      popOverContainer,
      classnames: cx,
      classPrefix: ns,
      children,
      closeOnClick,
      closeOnOutside
    } = props;
    const body = (
      <RootClose
        disabled={!isOpened}
        onRootClose={closeOnOutside !== false ? close : noop}
      >
        {(ref: any) => {
          return (
            <ul
              className={cx('ColumnToggler-menu')}
              onClick={closeOnClick ? close : noop}
              ref={ref}
            >
              {children}
            </ul>
          );
        }}
      </RootClose>
    );

    if (popOverContainer) {
      return (
        <Overlay container={popOverContainer} target={() => target.current} show>
          <PopOver
            overlay
            onHide={close}
            classPrefix={ns}
            className={cx('ColumnToggler-popover')}
            style={{ minWidth: (target.current as HTMLDivElement)?.offsetWidth }}
          >
            {body}
          </PopOver>
        </Overlay>
      );
    }

    return body;
  }

  const close = () => {
    setIsOpend(false)
    setTempColumns(columns)
    setSelectedTemp('')
  }

  // @autobind
  const onConfirm = () => {
    const { onColumnToggle } = props;
    const saveCols = productColumnInfo();
    const targetCol = columns.find(item => item.type === 'operation')
    const targetTemp = selectedTemp ? tempList.find(item => item.tempKey === selectedTemp) : undefined
    if (targetCol) {
      onColumnToggle && onColumnToggle([...sortColumns, targetCol as IColumn], saveCols, false, targetTemp);
    } else {
      onColumnToggle && onColumnToggle([...sortColumns], saveCols, false, targetTemp);
    }
    setIsOpend(false)
  }

  //计算出columnInfo数据
  const productColumnInfo = () => {
    const saveCols: SaveColType = {}
    sortColumns.forEach((col, index) => {
      if (col.type === 'operation') return;
      saveCols[col.name as string] = {
        index,
        hidden: col?.pristine?.hidden ? 1 : 0,
        fixed: col.fixed
      }
    })
    return saveCols
  }

  const initDragging = () => {
    const el = dialogRef?.current?.querySelector(
      `.${ns}ColumnToggler-modal-body-right .${ns}ColumnToggler-modal-content`
    ) as HTMLDivElement;
    if (el) {
      sortable.current = new Sortable(
        el,
        {
          group: `.${ns}ColumnToggler-modal-body-right`,
          animation: 150,
          // 提供class可拖动
          handle: `.${ns}ColumnToggler-menuItem`,
          ghostClass: `${ns}ColumnToggler-menuItem--dragging`,
          onEnd: (e: any) => {
            if (e.newIndex === e.oldIndex) {
              return;
            }

            // const parent = e.to as HTMLElement;
            // if (e.oldIndex < parent.childNodes.length - 1) {
            //   parent.insertBefore(e.item, parent.childNodes[e.oldIndex]);
            // } else {
            //   parent.appendChild(e.item);
            // }
            canConfirmFetch = true
            swapColumnPosition(e.oldIndex, e.newIndex);
          }
        }
      );
    }
  }

  const sortDel = (column: IColumn) => {
    const targetIndex = tempColumns.findIndex(item => item.name === column.name)
    updateToggledColumn(column, targetIndex, false)
  }

  const sortUp = (index: number, column: IColumn) => {
    if (index === 0) return;
    swapColumnPosition(index, index - 1)
  }

  const sortFix = (index: number, column: IColumn) => {
    const newSortColumns = [...sortColumns]
    const targetColumn = {
      ...column,
      fixed: column?.fixed ? '' : 'left',
    }
    newSortColumns.splice(index, 1, targetColumn)
    setSortColumns(newSortColumns)
  }

  const handleSelectAll = () => {
    let newtempColumns = tempColumns.map(item => ({
      ...item,
      pristine: { ...item?.pristine, hidden: selectAll ? true : false },
      toggled: selectAll ? false : true
    }))
    setTempColumns(newtempColumns)

    if (selectAll) {
      setSortColumns(newtempColumns)
    } else {
      const unSelList = tempColumns.filter(item => !item.toggled).map(item => ({
        ...item,
        pristine: { ...item?.pristine, hidden: false },
        toggled: true
      }))
      const newSortColumns = [...sortColumns]
      unSelList.map(item => {
        const targetIndex = newSortColumns.findIndex(sortItem => sortItem.name === item.name)
        targetIndex !== -1 && newSortColumns.splice(targetIndex, 1)
      })
      setSortColumns(newSortColumns.concat(unSelList))
    }
  }

  const saveTemplate = () => {
    setTempVisible(true)
  }

  const onOk = async () => {
    const values = await form.validateFields()
    if (editingTemp) {
      const data = {
        ...values,
        tempKey: editingTemp,
      }
      const { msg } = await env.fetcher({ url: `/api/v1/personal/setting/tempName/${props.crudName}`, method: 'post' }, data)
      message.info(msg)
    } else {
      const data = {
        ...values,
        tempKey: uuid(),
        columnInfo: productColumnInfo()
      }
      const api = normalizeApi(saveColApi?.url || '', 'post')
      const { msg } = await env.fetcher(api, data)
      message.info(msg)
    }
    await getTempList()
    setTempVisible(false)
  }

  const onSelect = (value: string) => {
    const target = tempList.find((item) => item.tempKey === value)
    const newtempColumns = Object.entries(target?.columnInfo || {}).map(([key, v]) => {
      const col = columns.find(item => item.name as string === key)
      return {
        ...col,
        index: v.index,
        toggled: !v?.hidden,
        fixed: v.fixed,
        pristine: { ...col?.pristine, hidden: !!v?.hidden }
      }
    }).sort((a, b) => a.index - b.index)
    setSelectedTemp(value)
    setTempColumns(newtempColumns as Array<IColumn>)
    setSortColumns(newtempColumns as Array<IColumn>)
  }

  const delTemp = async (tempKey: string) => {
    const api = normalizeApi({ url: saveColApi?.url || '', data: { tempKey }, method: 'delete' })
    const { msg } = await env.fetcher(api)
    message.info(msg)
    await getTempList()
  }

  const editTemp = (e: React.MouseEvent<HTMLSpanElement, MouseEvent>, tempKey: string, tempName: string) => {
    e.stopPropagation()
    form.setFieldsValue({ tempName })
    setTempVisible(true)
    setEditingTemp(tempKey)
  }

  const reset = () => {
    const colList = cloneDeep(columns).filter((item: IColumn) => item.type !== 'operation').map((item: IColumn) => {
      const index = $schema.columns.findIndex((col: IColumn) => col.name === item.name)
      return {
        ...item,
        toggled: true,
        index,
        pristine: { ...item?.pristine, hidden: false }
      }
    }).sort((a, b) => a.index - b.index)
    setTempColumns(colList)
    setSortColumns(colList)
  }

  const tempModalClose = () => {
    form.resetFields()
    setEditingTemp('')
  }

  return (
    <div
      className={cx(
        'ColumnToggler',
        {
          'ColumnToggler-block': block,
          'ColumnToggler--alignRight': align === 'right',
          'is-opened': isOpened,
          'is-actived': isActived
        },
        className
      )}
      ref={domRef}
    >
      {draggable ? (
        button
      ) : (
        <TooltipWrapper
          placement={placement}
          tooltip={disabled ? disabledTip : tooltip}
          container={tooltipContainer}
          trigger={tooltipTrigger}
          rootClose={tooltipRootClose}
        >
          {button}
        </TooltipWrapper>
      )}
      {isOpened && !draggable && renderOuter()}
      <TemplateModal visible={tempVisible} onOk={onOk} afterClose={tempModalClose} title="编辑配置名称"
        onCancel={() => setTempVisible(false)} okText={__('confirm')} cancelText={__('cancel')}>
        <Form form={form}>
          <Form.Item label="配置名称" name="tempName" rules={[{ required: true }]} >
            <Input />
          </Form.Item>
        </Form>
      </TemplateModal>
      <Modal
        size="lg"
        closeOnEsc
        onHide={close}
        show={isOpened && draggable}
        contentClassName={cx('ColumnToggler-modal')}
        container={modalContainer || target.current}
        overlay={typeof overlay === 'boolean' ? overlay : false}
      >
        <header className={cx('ColumnToggler-modal-header')}>
          <div style={{ width: 160, padding: '6px 0' }}>
            <Select getPopupContainer={env.getModalContainer} style={{ width: '100%' }} onSelect={onSelect} dropdownClassName='temp-selector-drop'>
              {
                tempList.map(item => (
                  <Select.Option value={item.tempKey} key={item.tempKey}>
                    <div style={{
                      minWidth: '30px', height: '100%', maxWidth: '90px', overflow: 'hidden',
                      textOverflow: 'ellipsis',
                      whiteSpace: 'nowrap'
                    }}>{item.tempName}</div>
                    <div className='temp-tools' onClick={(e) => e.stopPropagation()}>
                      <EditOutlined onClick={(e) => editTemp(e, item.tempKey, item.tempName)} />
                      <Popconfirm
                        title="确定要删除吗?"
                        onConfirm={() => delTemp(item.tempKey)}
                        // onCancel={cancel}
                        okText={__('confirm')}
                        cancelText={__('cancel')}
                      >
                        <DeleteOutlined />
                      </Popconfirm>

                    </div>
                  </Select.Option>
                ))
              }
            </Select>
          </div>
          <Button size="xs" level="link" onClick={saveTemplate}>保存为常用配置</Button>
        </header>
        <div className={cx('ColumnToggler-modal-body')} ref={dialogRef}>
          <div className={cx('ColumnToggler-modal-body-left')}>
            <div style={{ height: '32px', lineHeight: '32px' }}>
              <Button size="xs" level="link" onClick={handleSelectAll}>{selectAll ? '取消全选' : '全选'}</Button>
            </div>
            <ul className={cx('ColumnToggler-modal-content')}>
              {/* Jay */}
              {tempColumns.map((column, index) => column.type !== 'operation' ? (
                <TooltipWrapper
                  tooltipClassName={cx('ColumnToggler-tooltip')}
                  placement="top"
                  tooltip={column.label || ''}
                  trigger={'hover'}
                  key={column.index}
                >
                  <li
                    className={cx('ColumnToggler-menuItem')}
                    key={column.index}
                    // canSet为false不能设置显隐和排序
                    style={{ display: column?.pristine.canSet === false ? 'none' : 'block' }}
                  >
                    <Checkbox
                      size="sm"
                      classPrefix={ns}
                      checked={column?.pristine?.hidden ? false : column.toggled}
                      disabled={column?.toggable == false ? true : false}
                      onChange={(e: boolean) => updateToggledColumn(column, index, e)}
                    >
                      {/* Jay */}
                      {column.label ? render('tpl', column.label) : null}
                    </Checkbox>
                  </li>
                </TooltipWrapper>
              ) : null)}
            </ul>
          </div>
          <div className={cx('ColumnToggler-modal-body-right')} ref={dragRef}>
            <div style={{ height: '32px', fontSize: '12px', lineHeight: '32px', paddingLeft: '12px', color: '#a6abb4' }}>拖动或点击图标进行设置</div>
            <ul className={cx('ColumnToggler-modal-content')} style={{ overflowX: 'hidden' }}>
              {/* Jay */}
              {sortColumns.map((column, index) => (
                // <TooltipWrapper
                //   tooltipClassName={cx('ColumnToggler-tooltip')}
                //   placement="top"
                //   tooltip={column.label || ''}
                //   trigger={'hover'}
                //   key={column.index}
                // >
                <li
                  className={cx('ColumnToggler-menuItem') + `${column.fixed ? ' fixed-item' : ' normal-item'}`}
                  key={column.index}
                  //canSet为false不能设置显隐和排序
                  style={{ display: (column?.pristine?.hidden || !column.toggled || column?.pristine?.canSet === false) ? 'none' : 'block' }}
                >
                  <div style={{ display: 'flex', alignItems: 'center', height: '90%' }}>
                    <a className={cx('ColumnToggler-menuItem-dragBar')}>
                      <Icon icon="drag-bar" className={cx('icon')} />
                    </a>
                    <span style={{ flex: '0 0 80px' }}>
                      {column.label ? render('tpl', column.label) : null}
                    </span>
                    <div style={{ display: 'flex', justifyContent: 'flex-start', alignItems: 'center', marginLeft: 'auto' }}>
                      <CloseCircleOutlined title="隐藏" className='operation-icons' onClick={() => sortDel(column)} style={{ color: '#A5A5A5', marginLeft: 8 }} />
                      {index !== 0 && <VerticalAlignTopOutlined title="上移" className='operation-icons' onClick={() => sortUp(index, column)} style={{ color: '#A5A5A5', marginLeft: 8 }} />}
                      <PushpinOutlined title="固定" className={column.fixed ? '' : 'operation-icons'} onClick={() => sortFix(index, column)} style={{ color: '#A5A5A5', marginLeft: 8, transform: column.fixed ? 'rotate(-45deg)' : 'none' }} />
                    </div>
                  </div>
                </li>
                // </TooltipWrapper>
              ))}
            </ul>
          </div>
        </div>
        <footer className={cx('ColumnToggler-modal-footer')}>
          <div>
            <div>
              <Button size="sm" onClick={reset}>
                {__('resetSettings')}
              </Button>
            </div>
          </div>
          <div style={{ display: 'flex' }}>
            <div style={{ marginRight: 10 }}>
              <Button size="sm" onClick={close}>
                {__('cancel')}
              </Button>
            </div>
            <div>
              <Button level="primary" size="sm" onClick={onConfirm}>
                {__('confirm')}
              </Button>
            </div>
          </div>
        </footer>
      </Modal >
    </div >
  )
}
export default ColumnToggler;
