import React from 'react';
import {
  OptionsControl,
  OptionsControlProps,
  Option,
  FormOptionsControl
} from './Options';
import cx from 'classnames';
import { SchemaNode, Schema, Action, PlainObject } from '../../types';
import find from 'lodash/find';
import {
  anyChanged,
  autobind,
  getVariable,
  noop,
  createObject,
  isMobile,
  isNil
} from '../../utils/helper';
import findIndex from 'lodash/findIndex';
import Html from '../../components/Html';
import { filter } from '../../utils/tpl';
import { Icon } from '../../components/icons';
import { SchemaTpl } from '../../Schema';
import { isApiOutdated, isEffectiveApi } from '../../utils/api';
import { message, Modal, Popover } from 'antd';
import { handlelimitSize } from '../../utils/utils';
import { tools } from '../../utils/shell/tools';
import { copy } from '../Lion/utils/utils';

/**
 * Picker
 * 文档：https://baidu.gitee.io/amis/docs/components/form/picker
 */
export interface PickerControlSchema extends FormOptionsControl {
  type: 'picker';

  /**
   * 可用来生成选中的值的描述文字
   */
  labelTpl?: SchemaTpl;

  /**
   * 建议用 labelTpl
   * 选中一个字段名用来作为值的描述文字
   */
  labelField?: string;

  /**
   * 选一个可以用来作为值的字段。
   */
  valueField?: string;

  /**
   * 弹窗选择框详情。
   */
  pickerSchema?: any; // Omit<CRUDSchema, 'type'>;

  /**
   * 弹窗模式，dialog 或者 drawer
   */
  modalMode?: 'dialog' | 'drawer';

  /**
   * 内嵌模式，也就是说不弹框了。
   */
  embed?: boolean;

  /**
   * 最大选中个数
   */
  maxSelected?: number
  /**
   * 最小选中个数
   */
  minSelected?: number
}

export interface PickerProps extends OptionsControlProps {
  modalMode: 'dialog' | 'drawer';
  pickerSchema: PlainObject;
  labelField: string;
}

export interface PickerState {
  isOpened: boolean;
  isFocused: boolean;
  schema: SchemaNode;
  maxTagCount?: number
}

export default class PickerControl extends React.PureComponent<
  PickerProps,
  any
> {
  static propsList: Array<string> = [
    'modalMode',
    'pickerSchema',
    'labelField',
    'onChange',
    'options',
    'value',
    'inline',
    'multiple',
    'embed',
    'resetValue',
    'placeholder',
    'onQuery' // 防止 Form 的 onQuery 事件透传下去，不然会导致 table 先后触发 Form 和 Crud 的 onQuery
  ];
  static defaultProps: Partial<PickerProps> = {
    modalMode: 'dialog',
    multiple: false,
    placeholder: '请点击右侧的图标',
    labelField: 'label',
    valueField: 'value',
    pickerSchema: {
      mode: 'list',
      listItem: {
        title: '${label|raw}'
      }
    },
    embed: false
  };

  state: PickerState = {
    isOpened: false,
    schema: this.buildSchema(this.props),
    isFocused: false,
    maxTagCount: undefined
  };
  adaptation = React.createRef<any>();
  input: React.RefObject<HTMLInputElement> = React.createRef();

  componentDidMount() {
    if (!this.props.formItem) {
      this.fetchOptions();
    }
  }

  componentDidUpdate(prevProps: PickerProps) {
    const props = this.props;

    if (anyChanged(['pickerSchema', 'multiple', 'source'], prevProps, props)) {
      this.setState({
        schema: this.buildSchema(props)
      });
    } else if (
      JSON.stringify(props.value) !== JSON.stringify(prevProps.value)
    ) {
      if (!this.props.embed) {
        this.fetchOptions();
      }
    } else if (
      isApiOutdated(prevProps.source, props.source, prevProps.data, props.data)
    ) {
      this.fetchOptions();
    }
    // Jay form的数据域更新了
    if (prevProps.formInited === false && this.props.formInited) {
      if (!this.props.embed) {
        this.fetchOptions();
      }
    }
  }

  fetchOptions() {
    const { value, formItem, valueField, labelField, source, data } = this.props;
    let selectedOptions: any;

    if (
      !source ||
      !formItem ||
      (valueField || 'value') === (labelField || 'label') ||
      this.props.options.length && //Aug
      ((selectedOptions = formItem.getSelectedOptions(value)) &&
        (!selectedOptions.length ||
          selectedOptions[0][valueField || 'value'] !==
          selectedOptions[0][labelField || 'label']))
    ) {
      return;
    }

    if (isNil(value)) return

    const ctx = createObject(data, {
      value: value,
      op: 'loadOptions'
    });

    if (typeof source != 'string') {
      const newSource = { ...source, data: { ...source.data, [valueField]: value } }
      isEffectiveApi(newSource, ctx) && formItem.loadOptions(newSource, ctx, { autoAppend: true });
    } else {
      isEffectiveApi(source, ctx) && formItem.loadOptions(source, ctx, { autoAppend: true });
    }

  }

  buildSchema(props: PickerProps) {
    return {
      checkOnItemClick: true,
      ...props.pickerSchema,
      labelTpl: props.pickerSchema?.labelTpl ?? props.labelTpl,
      type: 'crud',
      pickerMode: true,
      syncLocation: false,
      api: props.source,
      keepItemSelectionOnPageChange: props.pickerSchema?.keepItemSelectionOnPageChange,
      valueField: props.valueField,
      labelField: props.labelField,
      // 不支持批量操作，会乱套
      bulkActions: props.multiple
        ? (props.pickerSchema as Schema).bulkActions
        : []
    };
  }

  crud: any;

  @autobind
  crudRef(ref: any) {
    while (ref && ref.getWrappedInstance) {
      ref = ref.getWrappedInstance();
    }
    this.crud = ref;
  }

  reload() {
    if (this.crud) {
      this.crud.search();
    } else {
      const reload = this.props.reloadOptions;
      reload && reload();
    }
  }

  @autobind
  open() {
    this.setState({
      isOpened: true
    });
  }

  @autobind
  close() {
    this.setState({
      isOpened: false
    });
  }

  @autobind
  handleModalConfirm(
    values: Array<any>,
    action: Action,
    ctx: any,
    components: Array<any>
  ) {
    const { maxSelected, minSelected } = this.props
    const idx = findIndex(
      components,
      (item: any) => item.props.type === 'crud'
    );

    if (values[idx].items) {
      values[idx].items
    }
    if (maxSelected !== undefined || minSelected !== undefined) {
      const dat = handlelimitSize(maxSelected, minSelected, values[idx].items, this.showModal.bind(this))
      if (!dat) return
    }
    this.handleChange(values[idx].items);
    this.close();
  }
  showModal(val?: string) {
    const { env, translate: __ } = this.props;
    Modal.warning({
      title: (
        <div>
          <div style={{ position: 'absolute', right: '10px', top: '10px', fontSize: '12px', cursor: "pointer" }} onClick={() => { Modal.destroyAll() }} >
            <Icon icon="close" className="icon" />
          </div>
        </div>
      ),
      content: val ?? '当前',
      getContainer: env.getModalContainer,
      zIndex: 1020,
      okText: __('confirm')
    });
  }


  @autobind
  handleChange(items: Array<any>) {
    const {
      joinValues,
      valueField,
      delimiter,
      extractValue,
      multiple,
      options,
      setOptions,
      onChange
    } = this.props;

    let value: any = items;

    if (joinValues) {
      value = items
        .map((item: any) => item[valueField || 'value'])
        .join(delimiter || ',');
    } else if (extractValue) {
      value = multiple
        ? items.map((item: any) => item[valueField || 'value'])
        : (items[0] && items[0][valueField || 'value']) || '';
    } else {
      value = multiple ? items : items[0];
    }

    let additionalOptions: Array<any> = [];
    items.forEach(item => {
      if (
        !find(
          options,
          option => item[valueField || 'value'] == option[valueField || 'value']
        )
      ) {
        additionalOptions.push(item);
      }
    });

    additionalOptions.length && setOptions(options.concat(additionalOptions));
    onChange(value);
  }

  removeItem = (index: number) => {
    const {
      selectedOptions,
      joinValues,
      extractValue,
      delimiter,
      valueField,
      onChange,
      multiple
    } = this.props;
    const items = selectedOptions.concat();
    items.splice(index, 1);

    let value: any = items;

    if (joinValues) {
      value = items
        .map((item: any) => item[valueField || 'value'])
        .join(delimiter || ',');
    } else if (extractValue) {
      value = multiple
        ? items.map((item: any) => item[valueField || 'value'])
        : (items[0] && items[0][valueField || 'value']) || '';
    } else {
      value = multiple ? items : items[0];
    }

    onChange(value);
  }

  @autobind
  handleKeyDown(e: React.KeyboardEvent) {
    const selectedOptions = this.props.selectedOptions;

    if (e.key === ' ') {
      this.open();
      e.preventDefault();
    } else if (selectedOptions.length && e.key == 'Backspace') {
      this.removeItem(selectedOptions.length - 1);
    }
  }

  @autobind
  handleFocus() {
    this.setState({
      isFocused: true
    });
  }

  @autobind
  handleBlur() {
    this.setState({
      isFocused: false
    });
  }

  @autobind
  handleClick() {
    this.input.current && this.input.current.focus();
  }

  @autobind
  clearValue() {
    const { onChange, resetValue } = this.props;
    onChange(resetValue !== void 0 ? resetValue : '');
  }

  renderValues() {
    const {
      classPrefix: ns,
      selectedOptions,
      delimiter,
      translate: __
    } = this.props;
    const value = selectedOptions.map((item) =>
      `${getVariable(item, this.props.labelField || 'label') || getVariable(item, 'id')}`).join(delimiter || ',')

    return <Popover
      trigger={'hover'}
      placement='top'
      className={cx(`${ns}Picker-valueWraps`)}
      getPopupContainer={() => document.getElementById('amis-modal-container')! || document.body}
      overlayClassName={cx(`${ns}Picker-ResultBox-overflow`)}
      content={
        tools.isPc && selectedOptions?.length ?
          <div className={cx(`${ns}Picker-values`)} onClick={(e) => { e.stopPropagation(); e.preventDefault(); }}>
            {selectedOptions?.length && selectedOptions?.length > 2 && <div key={'selectedOptions'} className={cx(`${ns}Picker-value`)} >
              {selectedOptions.length}
            </div>}
            {selectedOptions.map((item, index) => this.handleIten(item, index, true))}
            <span onClick={(e) => { e.stopPropagation(); e.preventDefault(); copy(value); message.success(__('System.copy')) }}>
              <Icon icon="copy" className="icon" />
            </span>
          </div> : null
      }
    >
      <div className={`${ns}Picker-values`} onClick={(e) => { e.stopPropagation() }}>
        {value}
      </div>
    </Popover>
    // return (
    //   <div className={`${ns}Picker-values`} onClick={(e) => { e.stopPropagation() }} >
    //     {selectedOptions.map((item, index) => this.handleIten(item, index))}
    //   </div>
    // );

  }
  handleIten(item: Option, index: number, bled?: boolean) {
    const {
      classPrefix: ns,
      labelField,
      labelTpl,
      disabled
    } = this.props;

    return (
      <div key={index} className={cx(`${ns}Picker-value`, `${bled ? ns + 'Picker-valueLabel-background' : ''}`, { 'is-disabled': disabled, })} >
        <span className={`${ns}Picker-valueLabel}`} onClick={() => { bled && !disabled && this.removeItem(index) }}>
          {labelTpl ? (
            <Html html={filter(labelTpl, item)} />
          ) : (
            `${getVariable(item, labelField || 'label') ||
            getVariable(item, 'id')}`)}
        </span>
        {bled || isMobile() || disabled ? null : <span
          data-tooltip="删除"
          data-position="bottom"
          className={`${ns}Picker-valueIcon`}
          onClick={(e) => {
            e.stopPropagation()
            this.removeItem(index)
          }}
        >
          <Icon icon="close" className="icon" />
        </span>}
      </div>)
  }
  @autobind
  renderBody({ popOverContainer }: any = {}) {
    const {
      render,
      selectedOptions,
      options,
      multiple,
      valueField,
      embed,
      source
    } = this.props;

    // Jay
    const props: any = {
      valueField,
      primaryField: valueField,
      options: source ? [] : options,
      multiple,
      onSelect: embed ? this.handleChange : undefined,
      ref: this.crudRef,
      popOverContainer
    }
    // embed为true时去掉value: selectedOptions，否则在某种情况下死循环
    // 死循环的原因可能是其他组件直接修改了value（该value是作为props，picker传递到其他组件）
    // 注释掉的话会导致其他组件拿不到选中值
    if (!embed) props.value = selectedOptions;
    props.isPick = true;
    const schema: any = this.state.schema

    return render('modal-body', { ...schema }, { ...schema, ...props, }) as JSX.Element;
  }

  render() {
    const {
      className,
      classnames: cx,
      disabled,
      render,
      modalMode,
      source,
      size,
      env,
      clearable,
      multiple,
      placeholder,
      embed,
      value,
      selectedOptions,
      translate: __,
      popOverContainer,
      formMode
    } = this.props;
    return (
      <div className={cx(`PickerControl`, className, formMode === 'inline' ? 'is-inline' : '')}>
        {embed ? (
          <div className={cx('Picker')}>
            {this.renderBody({ popOverContainer })}
          </div>
        ) : (
          <div
            className={cx(`Picker`, {
              'Picker--single': !multiple,
              'Picker--multi': multiple,
              'is-focused': this.state.isFocused,
              'is-disabled': disabled
            })}
          >
            <div onClick={this.handleClick} className={cx('Picker-input', isMobile() && 'isMobill-picker')}>
              {!selectedOptions.length && placeholder ? (
                <div className={cx('Picker-placeholder')}>
                  {__(placeholder)}
                </div>
              ) : null}

              <div className={cx('Picker-valueWrap')} ref={this.adaptation}>
                {this.renderValues()}

                <input
                  onChange={noop}
                  value={''}
                  ref={this.input}
                  onKeyDown={this.handleKeyDown}
                  // onFocus={this.handleFocus}
                  readOnly
                  onFocus={(e) => {
                    this.handleFocus()
                    this.open()
                  }}
                  onBlur={this.handleBlur}
                />
              </div>

              {clearable && !disabled && selectedOptions.length ? (
                <a onClick={this.clearValue} className={cx('Picker-clear')}>
                  <Icon icon="close" className="icon" />
                </a>
              ) : null}

              {!disabled && <span onClick={this.open} className={cx('Picker-btn')}>
                {isMobile() ?
                  <Icon icon="right-arrow-bold" className="icon" style={{ fontSize: '10px', color: "#0003" }} /> :
                  <Icon icon="window-restore" className="icon" />}
              </span>}
            </div>

            {this.state.isOpened ? render(
              'modal',
              {
                title: __('Select.placeholder'),
                size: size,
                type: modalMode,
                body: {
                  children: this.renderBody
                }
              },
              {
                key: 'modal',
                lazyRender: !!source,
                onConfirm: this.handleModalConfirm,
                onClose: this.close,
                show: this.state.isOpened,
                className: 'picker-modal'
              }
            ) : null}
          </div>
        )}
      </div>
    );
  }
}

@OptionsControl({
  type: 'picker',
  autoLoadOptionsFromSource: false,
  sizeMutable: false
})
export class PickerControlRenderer extends PickerControl { }
