/**
 * @file Alert
 * @author fex
 */

import React from 'react';
import { render } from 'react-dom';
import Modal from './Modal';
import Button from './Button';
import { themeable, ThemeProps } from '../theme';
import { LocaleProps, localeable } from '../locale';
import Html from './Html';
import { PlainObject } from '../types';
import { isMobile } from '../utils/helper';
import { Drawer, List, message, Table } from 'antd';
import { tools } from '../utils/shell/tools';
import { Icon } from './icons';
import { copy } from '../renderers/Lion/utils/utils';
import { handleHeader } from './Mobileprocess/utils';


export interface AlertProps extends ThemeProps, LocaleProps {
  container?: any;
  confirmText?: string;
  cancelText?: string;
  title?: string;
  confirmBtnLevel?: string;
  alertBtnLevel?: string;
}

export interface AlertState {
  show: boolean;
  title?: string;
  content: string | any;
  confirm: boolean;
  prompt?: boolean;
  controls?: any;
  value?: any;
  confirmText?: string;
  showCancel: boolean
}
interface appListBody {
  approverList: appList[],
  beforeTip: string,
}
interface appList {
  taskName: string,
  taskSeq: number,
  taskType: number,
  userId: string,
  userName: string
}
export class Alert extends React.Component<AlertProps, AlertState> {
  static instance: any = null;
  static getInstance() {
    if (!Alert.instance) {
      console.warn('Alert 组件应该没有被渲染，所以隐性的渲染到 body 了');
      const container = document.body;
      const div = document.createElement('div');
      container.appendChild(div);
      render(<FinnalAlert />, div);
    }

    return Alert.instance;
  }

  _resolve: (value: any) => void;
  _modal: any;
  _body: any;
  state: AlertState = {
    show: false,
    title: '',
    content: '',
    confirm: false,
    showCancel: true
  };
  constructor(props: AlertProps) {
    super(props);
    this.close = this.close.bind(this);
    this.handleConfirm = this.handleConfirm.bind(this);
    this.handleCancel = this.handleCancel.bind(this);
    this.modalRef = this.modalRef.bind(this);
    this.handleFormSubmit = this.handleFormSubmit.bind(this);
    this.scopeRef = this.scopeRef.bind(this);
    Alert.instance = this;

  }

  static defaultProps = {
    confirmText: 'confirm',
    cancelText: 'cancel',
    title: 'Alert.info',
    alertBtnLevel: 'primary',
    confirmBtnLevel: 'danger'
  };

  componentDidMount() {
    this._body && (this._body.innerHTML = this.state.content);
    this._modal && document.body.addEventListener('keyup', this.handleKeyPress);
  }

  handleKeyPress = (e: KeyboardEvent) => {
    if (e.key === 'Enter' && !this.state.prompt) {
      this.handleConfirm()
    }
  }

  componentDidUpdate(prevProps: AlertProps, prevState: AlertState) {
    if (prevState.content !== this.state.content) {
      this._body && (this._body.innerHTML = this.state.content);
    }
  }

  componentWillUnmount() {
    Alert.instance = null;

    document.body.removeEventListener('keyup', this.handleKeyPress);
  }

  schemaSope: any;
  scopeRef(schemaSope: any) {
    this.schemaSope = schemaSope;
  }

  handleConfirm() {
    const form = this.schemaSope?.getComponentByName('form');

    if (form) {
      form.doAction({ type: 'submit' });
    } else {
      this.close(true);
    }
  }

  handleCancel() {
    this.close(false);
  }

  close(confirmed: boolean) {
    const isConfirm = this.state.confirm || this.state.prompt;

    this.setState(
      {
        show: false,
        prompt: false,
        confirm: false,
        showCancel: true
      },
      isConfirm ? () => this._resolve(confirmed) /*this._reject()*/ : undefined
    );
  }

  reAddlisten() {
    // 防止打开稍微延时就引起了输入造成闪动
    this._modal && document.body.removeEventListener('keyup', this.handleKeyPress);
    setTimeout(() => {
      this._modal && document.body.addEventListener('keyup', this.handleKeyPress);
    }, 200)
  }

  alert(content: string, title?: string) {
    this.reAddlisten()
    this.setState({
      title,
      content,
      show: true,
      confirm: false
    });
  }

  confirm(content: string, title?: string, confirmText?: string, showCancel: boolean = true) {
    this.reAddlisten()
    this.setState({
      title,
      content,
      show: true,
      confirm: true,
      confirmText,
      showCancel
    });

    return new Promise(resolve => {
      this._resolve = resolve;
    });
  }

  prompt(
    controls: any,
    defaultValue?: any,
    title: string = 'placeholder.enter',
    confirmText: string = 'confirm'
  ) {
    if (typeof controls === 'string') {
      // 兼容浏览器标准用法。
      controls = [
        {
          name: 'text',
          label: controls,
          type: 'text'
        }
      ];

      if (typeof defaultValue === 'string') {
        defaultValue = {
          text: defaultValue
        };
      }
    } else if (!Array.isArray(controls)) {
      controls = [controls];
    }

    this.setState({
      title,
      controls,
      show: true,
      prompt: true,
      value: defaultValue,
      confirmText
    });

    return new Promise(resolve => {
      this._resolve = resolve;
    });
  }

  modalRef(ref: any) {
    this._modal = ref;
  }

  handleFormSubmit(values: any) {
    this.close(values);
  }

  handleSignature(body: appListBody) {
    const { translate: __ } = this.props
    const { approverList, beforeTip } = body
    const columns = [
      {
        title: __('Alert.sequence'),
        dataIndex: 'index',
        key: 'index',
        width: '20%'
      },
      {
        title: __('Alert.people'),
        dataIndex: 'userName',
        key: 'userName',
        width: '30%'
      },
      {
        title: __('Alert.role'),
        dataIndex: 'taskName',
        key: 'taskName',
        width: '30%'
      },
      {
        title: __('Alert.type'),
        dataIndex: 'taskType',
        key: 'taskType',
        width: '20%'
      }
    ]
    const data = approverList.map(item => item)
    const dataSource = data?.sort((a, b) => a.taskSeq - b.taskSeq)?.map((item) => {
      return {
        index: item.taskSeq,
        userName: item.userName + "(" + item.userId + ")",
        taskType: item.taskType == 0 ? '或签' : '会签',
        taskName: item.taskName,
        taskSeq: item.taskSeq
      }
    })
    return <>
      {
        isMobile() ? <Drawer
          className='process_drawer'
          closable={false}
          width={"100%"}
          visible={this.state.show}
          mask={false}
          destroyOnClose
          zIndex={1011}
          bodyStyle={{ backgroundColor: '#fff' }}
          getContainer={this.props.container}
          footer={
            <div style={{ textAlign: 'right' }}>
              <Button onClick={() => this.handleCancel()} >
                取消
              </Button>
              <span> </span>
              <Button level='primary' onClick={() => this.handleConfirm()}>
                确定送签
              </Button>
            </div>
          }
        >
          {handleHeader(() => this.handleCancel(), tools.isComWx ? '' : '送签')}
          <div style={{ overflow: "auto", flex: 1, padding: '10px 20px' }}>
            {beforeTip && <div>
              {beforeTip}
            </div>}
            <List
              itemLayout="horizontal"
              dataSource={dataSource}
              renderItem={(item, index) => (
                <List.Item key={index}>
                  <List.Item.Meta
                    avatar={item.index}
                    title={<div
                      style={{
                        fontSize: '14px',
                        color: "#000000e6"
                      }}>{item.userName}</div>
                    }
                    description={<div style={{ fontSize: '12px' }}>{item.taskName}</div>}
                  />
                  <div style={{ fontSize: '12px', color: "#00000066" }}>
                    {item.taskType}
                  </div>
                </List.Item>
              )}
            />
          </div>

        </Drawer> :
          <>
            {beforeTip && <div>
              {beforeTip}
            </div>}
            <div style={{ border: "1px solid rgba(0, 0, 0, 0.05)", borderBottom: 'none' }}>
              <Table columns={columns} size='small' dataSource={dataSource} pagination={false} />
            </div>
          </>
      }
    </>
  }
  render() {
    const {
      container,
      cancelText,
      confirmText,
      title,
      confirmBtnLevel,
      alertBtnLevel,
      classnames: cx,
      className
    } = this.props;
    let theme = this.props.theme || 'cxd';
    if (theme === 'default') {
      theme = 'cxd';
    }
    const data = (this.state.content as any)?.data
    const __ = this.props.translate;
    const finalConfirmText = data ? __('Flow.confirm.signature.submission') : __(this.state.confirmText ?? confirmText);
    const finalTitle = data ? __('Flow.send.for.signature') : __(this.state.title ?? title);


    return data && isMobile() ? <>
      {this.handleSignature(data)}
    </> : (
      <Modal
        show={this.state.show}
        onHide={this.handleCancel}
        container={document.getElementById('amis-modal-container') || container}
        ref={this.modalRef}
        style={{ zIndex: '1010' }}
        closeOnEsc
        className={cx(
          {
            [`Modal--center`]: data
          },
          className
        )}
      >
        {finalTitle ? (
          <div className={cx('Modal-header')}>
            <div className={cx('Modal-title')}>{finalTitle}</div>
          </div>
        ) : null}
        <div className={cx('Modal-body')}>
          {this.state.prompt ? (
            renderForm(
              this.state.controls,
              this.state.value,
              this.handleFormSubmit,
              this.scopeRef,
              theme,
              true,
              true
            )
          ) : (
            <>
              {
                data ?
                  this.handleSignature(data) : <>
                    <Html html={this.state.content} />
                    <Icon icon={"copy"} className="icon" style={{ fontSize: '14px', cursor: 'pointer', marginLeft: '5px' }} onClick={async () => {
                      await copy(this.state.content);
                      message.success(__('System.copy'))
                    }} />
                  </>
              }
            </>
          )}
        </div>
        {finalConfirmText ? (
          <div className={cx('Modal-footer')}>
            {(this.state.confirm || this.state.prompt) ? (
              this.state.showCancel ? <Button onClick={this.handleCancel}>{__(cancelText)}</Button> : null
            ) : null}
            <Button
              level={
                this.state.confirm || this.state.prompt
                  ? (data || !this.state.showCancel ? alertBtnLevel : confirmBtnLevel)
                  : alertBtnLevel
              }
              onClick={this.handleConfirm}
            >
              {finalConfirmText}
            </Button>
          </div>
        ) : null}
      </Modal>
    );
  }
}

export type renderSchemaFn = (
  controls: Array<any>,
  value: PlainObject,
  callback?: (values: PlainObject) => void,
  scopeRef?: (value: any) => void,
  theme?: string,
  inModal?: boolean,
  autoFocus?: boolean
) => JSX.Element;
let renderSchemaFn: renderSchemaFn;
export function setRenderSchemaFn(fn: renderSchemaFn) {
  renderSchemaFn = fn;
}

function renderForm(
  controls: Array<any>,
  value: PlainObject = {},
  callback?: (values: PlainObject) => void,
  scopeRef?: (value: any) => void,
  theme?: string,
  inModal?: boolean,
  autoFocus?: boolean
) {
  return renderSchemaFn?.(controls, value, callback, scopeRef, theme, inModal, autoFocus);
}

export const alert: (content: string, title?: string) => void = (
  content,
  title
) => Alert.getInstance().alert(content, title);
export const confirm: (
  content: string,
  title?: string,
  confirmText?: string,
  showCancel?: boolean
) => Promise<any> = (content, title, confirmText, showCancel) =>
    Alert.getInstance().confirm(content, title, confirmText, showCancel);
export const prompt: (
  controls: any,
  defaultvalue?: any,
  title?: string,
  confirmText?: string
) => Promise<any> = (controls, defaultvalue, title, confirmText) =>
    Alert.getInstance().prompt(controls, defaultvalue, title, confirmText);
export const FinnalAlert = themeable(localeable(Alert));
export default FinnalAlert;
