import React from 'react'
import { Col, Row } from 'antd/lib/grid'
import Progress from 'antd/lib/progress'
import Spin from 'antd/lib/spin'
import { Renderer, RendererProps } from '../../../factory'
import { BaseSchema, SchemaApi } from '../../../Schema'
import { Icon } from '../../../components/icons'
import { deepCalcFn } from '../../../utils/utils'
import isEqual from 'lodash/isEqual'
import { IScopedContext, ScopedContext } from '../../../Scoped'

export interface DataDisplaySchema extends BaseSchema {
  type: 'data-display'
  api: SchemaApi
  showFold: boolean
  /** 
   * 每行展示分组个数
   */
  groupRowNum: number
 /**
  *  每行展示分组宽度
  */
  groupWidth: number
  /**
  * 一个分组的每行展示字段个数
  */
  columnNum: number
   /**
   * 每行分组宽度,大于0则columnNum不生效
   */
  columnWidth: number
  /**
   * 分组字段
   */
  groupField: string
  /**
  * 分组背景色字段
  */
  groupBgColorField?: string
  /**
  * 分组描述字段
  */
  groupDescField?: string
  /**
   * 分组border大小字段
   */
  groupBorderSizeField?: string
  /**
   * 分组border颜色字段
   */
  groupBorderColorField?: string
  /**
   * 分组padding大小字段
   */
  groupPaddingField?: string
  /**
  * 图标字段
  */
  iconField?: string
  /**
   * 图标颜色
   */
  iconColorField?: string
  /**
  * 指标描述字段
  */
  labelDescField?: string
  /**
  * 指标内容展示方向 0:水平 1:垂直
  */
  labelDirection: 0 | 1
  /**
  * 指标名称字段
  */
  labelNameField: string
  /**
   * 指标名称颜色字段
   */
  labelNameColorField?: string
  /**
  * 指标值字段
  */
  labelValueField: string
  /**
   * 指标值表达式字段,对应的值不为空时根据items计算表达式值,labelValueField不生效
   */
  valueFormulaField?: string
  /**
  * 指标值字体颜色字段
  */
  labelFontColorField?: string
  /**
  * 指标值字体大小字段
  */
  labelFontSizeField?: string
  /**
  * 进度条value字段
  */
  progressField?: string
  /**
  * 进度条位置字段 0:左 1:右 2:上 3:下
  */
  progressPositionField?: string
  /**
   * 进度条类型字段 0:环形 1:条形
   */
  progressTypeField?: string
  /**
   * 进度条颜色字段
   */
  progressColorField?: string
  /**
   * 指标linkUrl字段
   */
  linkUrlField?: string
  /**
  * 指标linkTitle字段
  */
  linkTitleField?: string
  /**
  * 指标linkId字段
  */
  linkPageField?: string
  items?: any[]
  query?: object
}

export interface DataDisplayProps extends RendererProps, Omit<DataDisplaySchema, 'type' | 'className'> { }

interface DataDisplayState {
  data: IDisplayData[]
  loading: boolean
}

interface ILabel {
  labelName: string,
  labelValue: string
  labelNameColor?: string
  labelIcon?: string
  labelIconColor?: string
  labelDesc?: string
  labelFontSize?: string
  labelFontColor?: string
  linkId?: string
  linkUrl?: string
  linkTitle?: string
}

interface IDisplayData {
  groupId: string | number
  groupName: string | null
  groupDesc?: string
  groupBg?: string
  groupPadding?: string
  groupBorderSize?: number
  groupBorderColor?: string
  /**
  * 进度条类型字段 0:环形 1:条形
  */
  progressType?: 0 | 1
  /**
  * 进度条位置字段 0:左 1:右 2:上 3:下
  */
  progressPosition?: 0 | 1 | 2 | 3
  progressColor?: string
  progressValue?: number
  /** 实时计算高度 */
  progressWidth?: number
  labels: ILabel[]
}

export class DataDisplay extends React.Component<DataDisplayProps, DataDisplayState> {

  ref: React.RefObject<HTMLDivElement>;

  static defaultProps: Partial<DataDisplaySchema> = {
    columnNum: 1,
    groupRowNum: 1,
    columnWidth: 0,
    groupWidth: 0,
    showFold: false
  }

  constructor(props: DataDisplayProps) {
    super(props)
    this.state = {
      loading: true,
      data: [],
    }
    this.ref = React.createRef()
    this.calcProgressAndColumnWidth = this.calcProgressAndColumnWidth.bind(this)
  }

  componentDidMount() {
    this.getData()
  }

  async getData(params?: object) {
    const { env, api, query = {}, items, groupWidth,
      groupField, groupDescField, groupBgColorField, iconField, iconColorField, groupBorderColorField, groupBorderSizeField, groupPaddingField,
      labelNameField, labelNameColorField, labelValueField, valueFormulaField, labelDescField, labelFontSizeField, labelFontColorField,
      progressTypeField, progressPositionField, progressColorField, progressField,
      linkUrlField, linkPageField, linkTitleField
    } = this.props

    const payload = await env.fetcher(api, { ...query, ...params }).finally(() => this.setState({ loading: false }))
    if (payload.ok && Array.isArray(payload.data)) {
      const data = payload.data.reduce<IDisplayData[]>((pre, current, curentIndex) => {
        const index = pre.findIndex(item => item.groupId == current[groupField])
        if (index == -1) {
          pre.push({
            groupId: current[groupField] || curentIndex,
            groupName: current[groupField],
            groupDesc: groupDescField ? current[groupDescField] : undefined,
            groupBg: groupBgColorField ? current[groupBgColorField] : undefined,
            groupPadding: groupPaddingField ? current[groupPaddingField] : undefined,
            groupBorderColor: groupBorderColorField ? current[groupBorderColorField] ?? undefined : undefined,
            groupBorderSize: groupBorderSizeField ? current[groupBorderSizeField] ?? undefined : undefined,
            progressType: progressTypeField ? current[progressTypeField] : undefined,
            progressPosition: progressPositionField ? current[progressPositionField] : undefined,
            progressColor: progressColorField ? current[progressColorField] : undefined,
            progressValue: progressField ? current[progressField] ?? undefined : undefined,
            labels: [{
              labelName: current[labelNameField],
              labelValue: (valueFormulaField && current[valueFormulaField]) ? deepCalcFn(current[valueFormulaField], items ?? []) : current[labelValueField],
              labelNameColor: labelNameColorField ? current[labelNameColorField] : undefined,
              labelIcon: iconField ? current[iconField] : undefined,
              labelIconColor: iconColorField ? current[iconColorField] : undefined,
              labelDesc: labelDescField ? current[labelDescField] : undefined,
              labelFontSize: labelFontSizeField ? current[labelFontSizeField] : undefined,
              labelFontColor: labelFontColorField ? current[labelFontColorField] : undefined,
              linkUrl: linkUrlField ? current[linkUrlField] : undefined,
              linkId: linkPageField ? current[linkPageField] : undefined,
              linkTitle: linkTitleField ? current[linkTitleField] : undefined
            }]
          })
        } else {
          pre[index].labels.push({
            labelName: current[labelNameField],
            labelValue: (valueFormulaField && current[valueFormulaField]) ? deepCalcFn(current[valueFormulaField], items ?? []) : current[labelValueField],
            labelNameColor: labelNameColorField ? current[labelNameColorField] : undefined,
            labelIcon: iconField ? current[iconField] : undefined,
            labelIconColor: iconColorField ? current[iconColorField] : undefined,
            labelDesc: labelDescField ? current[labelDescField] : undefined,
            labelFontSize: labelFontSizeField ? current[labelFontSizeField] : undefined,
            labelFontColor: labelFontColorField ? current[labelFontColorField] : undefined,
            linkUrl: linkUrlField ? current[linkUrlField] : undefined,
            linkId: linkPageField ? current[linkPageField] : undefined,
            linkTitle: linkTitleField ? current[linkTitleField] : undefined
          })
        }
        return pre
      }, [])
      if ((this.ref.current?.clientWidth ?? 0) > 0 && groupWidth > 0) {
        const width = this.ref.current!.clientWidth
        const count = Math.floor(width / groupWidth)
        const restCount = count - (data.length % count)
        for (let i = 0; i < restCount; i++) {
          data.push({ groupId: i + data.length, groupName: null, labels: [] })
        }
      }
      // console.log(data)
      this.setState({ data }, this.calcProgressAndColumnWidth)
    }
  }

  calcProgressAndColumnWidth() {
    this.setState((pre) => {
      const newData = pre.data.map(item => {
        const element = this.ref.current?.getElementsByClassName('item-' + item.groupId)[0]
        const width = element ? (element.clientHeight - 16) > 45 ? (element.clientHeight - 16) : 45 : 45
        const columnWidth = this.props.columnWidth
        const labels = item.labels
        if ((element?.clientWidth ?? 0) > 0 && columnWidth > 0) {
          const count = Math.floor(element?.clientWidth! / columnWidth)
          const restCount = count - (labels.length % count)
          for (let i = 0; i < restCount; i++) {
            labels.push({ labelName: '', labelValue: '' })
          }
        }
        return { ...item, progressWidth: width }
      })
      return { data: newData }
    })
  }

  handleLink(label: ILabel) {
    if (label.linkUrl) {
      const id = 'Matrix' + (label.linkId ?? Date.now().toString())
      this.props.env.onPageLink?.(id, id, label.linkTitle ?? label.labelName, label.linkUrl, undefined)
    }
  }

  componentDidUpdate(preProps: DataDisplayProps) {
    if (!isEqual(preProps.items ?? [], this.props.items ?? [])) {
      this.getData()
    }
  }

  render() {
    const { groupRowNum, groupWidth, columnNum, columnWidth, labelDirection } = this.props
    const { data, loading } = this.state
    const isTile = data.every(item => item.groupName == null)

    return (
      <div className={`data-display`} ref={this.ref}>
        <Spin className='data-display-spin' spinning={loading} />
        <Row gutter={[8, 8]} justify={groupWidth > 0 ? 'space-between' : undefined}>
          {data.map(item => {
            const { groupId, groupName, groupDesc, groupBg, groupPadding, groupBorderColor, groupBorderSize ,labels, progressType, progressPosition, progressColor, progressValue, progressWidth = 45 } = item
            const hasProgress = progressType != undefined && progressPosition != undefined
            const progressInLeftOrRight = progressPosition == 0 || progressPosition == 1
            return (
              <Col 
                key={groupId} 
                style={{ 
                  display: 'block', 
                  width: groupWidth > 0 ? groupWidth : undefined,
                  flex: groupWidth > 0 ? undefined : `0 0 ${(100 / (groupRowNum || data.length))}%`,
                  maxWidth: groupWidth > 0 ? undefined : `${(100 / (groupRowNum || data.length))}%`
                }}
              >
                <div className='data-display-item' style={{ backgroundColor: groupBg, borderColor: groupBorderColor, borderWidth: groupBorderSize, padding: groupPadding }}>
                  {(groupName?.trim() || groupDesc?.trim()) && (
                    <div className='data-display-item-group'>
                      <span className='group-title'>{groupName}</span>
                      <span className='group-desc'>{groupDesc}</span>
                    </div>
                  )}
                  {labelDirection == 0 && (
                    <div style={{ display: hasProgress ? 'flex' : undefined, alignItems: hasProgress && progressInLeftOrRight ? 'center' : undefined, flexDirection: hasProgress ? progressInLeftOrRight ? 'row' : 'column' : undefined }}>
                      {(hasProgress && (progressPosition == 0 || progressPosition == 2)) &&
                        <Progress
                          size='small'
                          width={progressWidth}
                          type={progressType == 0 ? 'circle' : 'line'}
                          status='normal'
                          percent={progressValue}
                          format={percent => <div style={{ fontSize: progressType == 0 ? 14 : 12 }}>{percent}%</div>}
                          strokeWidth={10}
                          strokeColor={progressColor}
                          strokeLinecap='butt'
                          style={{ marginRight: progressPosition == 0 ? 16 : undefined, marginBottom: progressPosition == 2 ? 8 : undefined }}
                        />}
                      <Row className={`data-display-item-labels item-${item.groupId}`} gutter={[16, 12]} justify={columnWidth > 0 ? 'space-between' : undefined}>
                        {labels.map((label, index) => (
                          <Col
                            key={index}
                            span={isTile ? 24 : undefined}
                            style={isTile ? undefined : {
                              display: 'block',
                              width: columnWidth > 0 ? columnWidth : undefined,
                              flex: columnWidth > 0 ? undefined : `0 0 ${(100 / (columnNum || labels.length))}%`,
                              maxWidth: columnWidth > 0 ? undefined : `${(100 / (columnNum || labels.length))}%`
                            }}
                            className={label.linkUrl ? 'link' : undefined}
                            onClick={this.handleLink.bind(this, label)}
                          >
                            <div className='data-display-item-labels-item'>
                              <div className='wrap'>
                                <div className={label.labelDesc ? 'left' : undefined}>
                                  {label.labelIcon && <Icon icon={label.labelIcon} style={{ fontSize: label.labelDesc ? 38 : 38, color: label.labelIconColor ?? 'aqua' }} symbol />}
                                </div>
                                <div className='right'>
                                  <div className='data-display-item-labels-item-header'>
                                    <div className='sub-title' style={{ color: label.labelNameColor }}>{label.labelName}</div>
                                    <div className='title' style={{ fontSize: label.labelFontSize, color: label.labelFontColor }}>{label.labelValue}</div>
                                  </div>
                                  {label.labelDesc && <div className='desc'>{label.labelDesc.split('<br/>').map((str, index) => <p key={index}>{str}</p>)}</div>}
                                </div>
                              </div>
                            </div>
                          </Col>
                        ))}
                      </Row>
                      {(hasProgress && (progressPosition == 1 || progressPosition == 3)) &&
                        <Progress
                          size='small'
                          width={progressWidth}
                          type={progressType == 0 ? 'circle' : 'line'}
                          status='normal'
                          percent={progressValue}
                          format={percent => <div style={{ fontSize: progressType == 0 ? 14 : 12 }}>{percent}%</div>}
                          strokeWidth={10}
                          strokeColor={progressColor}
                          strokeLinecap='butt'
                          style={{ marginLeft: progressPosition == 1 ? 16 : undefined, marginTop: progressPosition == 3 ? 8 : undefined }}
                        />}
                    </div>
                  )}
                  {labelDirection == 1 && (
                    <div style={{ display: hasProgress ? 'flex' : undefined, alignItems: hasProgress && progressInLeftOrRight ? 'center' : undefined, flexDirection: hasProgress ? progressInLeftOrRight ? 'row' : 'column' : undefined }}>
                      {(hasProgress && (progressPosition == 0 || progressPosition == 2)) &&
                        <Progress
                          size='small'
                          width={progressWidth}
                          type={progressType == 0 ? 'circle' : 'line'}
                          status='normal'
                          percent={progressValue}
                          format={percent => <div style={{ fontSize: progressType == 0 ? 14 : 12 }}>{percent}%</div>}
                          strokeWidth={10}
                          strokeColor={progressColor}
                          strokeLinecap='butt'
                          style={{ marginRight: progressPosition == 0 ? 16 : undefined, marginBottom: progressPosition == 2 ? 8 : undefined }}
                        />}
                      <Row className={`data-display-item-vertical-labels item-${item.groupId}`} gutter={[12, 12]} justify={columnWidth > 0 ? 'space-between' : undefined}>
                        {labels.map((label, index) => (
                          <Col 
                            key={index} 
                            span={isTile ? 24 : undefined}
                            style={isTile ? undefined : { 
                              display: 'block', 
                              width: columnWidth > 0 ? columnWidth : undefined,
                              flex: columnWidth > 0 ? undefined : `0 0 ${(100 / (columnNum || labels.length))}%`,
                              maxWidth: columnWidth > 0 ? undefined : `${(100 / (columnNum || labels.length))}%`
                            }}
                            className={label.linkUrl ? 'link' : undefined} 
                            onClick={this.handleLink.bind(this, label)}
                          >
                            <div className='data-display-item-vertical-labels-item'>
                              <div className='wrap'>
                                {label.labelIcon && <div><Icon icon={label.labelIcon} style={{ fontSize: label.labelDesc ? 38 : 38, color: label.labelIconColor }} symbol /></div>}
                                <div className='right'>
                                  <div className='sub-title' style={{ color: label.labelNameColor }}>{label.labelName}</div>
                                  <div className='title' style={{ fontSize: label.labelFontSize, color: label.labelFontColor }}>{label.labelValue}</div>
                                  {label.labelDesc && <div className='desc'> {label.labelDesc.split('<br/>').map((str, index) => <p key={index}>{str}</p>)}</div>}
                                </div>
                              </div>
                            </div>
                          </Col>
                        ))}
                      </Row>
                      {(hasProgress && (progressPosition == 1 || progressPosition == 3)) &&
                        <Progress
                          size='small'
                          type={progressType == 0 ? 'circle' : 'line'}
                          width={progressWidth}
                          status='normal'
                          percent={progressValue}
                          format={percent => <div style={{ fontSize: progressType == 0 ? 14 : 12 }}>{percent}%</div>}
                          strokeWidth={10}
                          strokeLinecap='butt'
                          strokeColor={progressColor}
                          style={{ marginLeft: progressPosition == 1 ? 16 : undefined, marginTop: progressPosition == 3 ? 8 : undefined }}
                        />}
                    </div>
                  )}
                </div>
              </Col>
            )
          })}
        </Row>
      </div>
    )
  }
}

@Renderer({ type: 'data-display' })
export class DataDisplayRenderer extends DataDisplay { 

  static contextType = ScopedContext;
  constructor(props: DataDisplayProps, context: IScopedContext) {
    super(props);
    const scoped = context;
    scoped.registerComponent(this);
  }

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

  receive(values: any) {
    return super.getData(values);
  }

}
