import React from 'react'
import { Select, Switch, message } from 'antd'
import i18n from 'i18next'
import cls from 'classnames'
import treeActions from 'actions/tree'
import uiActions from 'actions/ui'
import serviceActions from 'actions/service'
import widgetStore from 'stores/widget'
import treeStore from 'stores/tree'
import newEventStores from 'stores/newEvent'
import serviceStore from 'stores/service'
import { getEventNodeById } from 'stores/funcs/newEvent'
import { isValidParamName } from 'stores/funcs/event/eventUtils'
import { nodeIsNormalService } from 'stores/funcs/nodeType'
import { saveCaseBeforeActions } from 'stores/funcs/service'
import propType from 'const/propType'

const { Option } = Select

export default class NodeServiceParams extends React.Component {
  constructor(props) {
    super(props)
    this.state = {
      inParams: this.getInParams(),
      outParams: this.getOutParams(),
      title: this.getTitleName(),
      paramWarning: undefined,
      allowConfigShare: false, // true, false, reload, loading
      isShared: false,
      sharedTitle: '', // 服务的title
      sharedDesc: '' // 服务的desc
    }
    this.sharedServiceInfo = undefined // 读取的共享服务信息需要使用的部分
    this.types = [
      {
        name: i18n.t('FunctionView.Any'),
        value: 'undefined'
      },
      {
        name: i18n.t('FunctionView.Number'),
        value: propType.Number
      },
      {
        name: i18n.t('FunctionView.String'),
        value: propType.String
      },
      {
        name: i18n.t('FunctionView.Boolean'),
        value: propType.Boolean
      },
      {
        name: i18n.t('FunctionView.Object'),
        value: 'Object'
      }
    ]
    this.loadSharedService = this.loadSharedService.bind(this)
    this.configResult = this.configResult.bind(this)
    this.reloadAction = this.reloadAction.bind(this)
    this.onAddParam = this.onAddParam.bind(this)
    this.saveCase = this.saveCase.bind(this)
    this.onChangeShared = this.onChangeShared.bind(this)
    this.onChangeSharedInfo = this.onChangeSharedInfo.bind(this)
    this.getSharedData = this.getSharedData.bind(this)
    this.addShareData = this.addShareData.bind(this)
    this.modifySharedData = this.modifySharedData.bind(this)
    this.deleteShareData = this.deleteShareData.bind(this)

    this.getInParams = this.getInParams.bind(this)
    this.getOutParams = this.getOutParams.bind(this)
    this.getInParamsName = this.getInParamsName.bind(this)
    this.getOutParamsName = this.getOutParamsName.bind(this)
    this.getTitleName = this.getTitleName.bind(this)

    this.genAddButton = this.genAddButton.bind(this)
    this.getInParamsCom = this.getInParamsCom.bind(this)
    this.genInput = this.genInput.bind(this)
    this.genError = this.genError.bind(this)
    this.getSharedConfig = this.getSharedConfig.bind(this)
  }

  componentDidMount() {
    this.loadSharedService()
  }

  componentDidUpdate(preProps) {
    if (preProps.nodeId !== this.props.nodeId) {
      this.setState(
        {
          inParams: this.getInParams(),
          outParams: this.getOutParams(),
          title: this.getTitleName(),
          paramWarning: undefined,
          allowConfigShare: false
        },
        () => {
          this.loadSharedService()
        }
      )
    }
  }

  loadSharedService() {
    // 小模块不需要
    if (
      treeStore.curClassId ||
      !(treeStore.curCaseInfo.eid || treeStore.curCaseInfo.gid)
    ) {
      this.setState({
        allowConfigShare: false
      })
      return
    }
    let nodeId = this.props.nodeId
    let node = getEventNodeById(nodeId)
    if (nodeIsNormalService(node && node.type)) {
      this.setState({
        allowConfigShare: 'loading'
      })
      serviceStore.loadSharedService({ nodeId }).then(result => {
        // 保证修改的nodeId正确
        let _nodeId = result && result.nodeId
        if (_nodeId !== nodeId) {
          return
        }
        let obj = {
          allowConfigShare: true
        }
        this.sharedServiceInfo = undefined
        if (result === false) {
          obj.allowConfigShare = 'reload'
        } else if (result && result.id) {
          obj.isShared = true
          obj = this.configResult(obj, result, nodeId)
        } else {
          obj.isShared = false
          obj.inParams = []
          obj.outParams = []
          let node = getEventNodeById(nodeId)
          if (node) {
            obj.inParams = node.props.inParams || []
            obj.outParams = node.props.outParams || []
          }
        }
        this.setState(obj)
      })
    } else {
      this.setState({
        allowConfigShare: false
      })
    }
  }

  configResult(obj, result, nodeId) {
    this.sharedServiceInfo = { id: result.id, uri: result.uri, gid: result.gid } // 记录当前的共享服务id
    if (result.content) {
      let params = undefined
      try {
        params = JSON.parse(result.content)
      } catch (e) {}
      if (params) {
        obj.sharedTitle = result.filename
        obj.sharedDesc = params.desc
        let inParams = params.inParams || []
        let outParams = params.outParams || []
        let inParamsSame = false
        let outParamsSame = false
        try {
          inParamsSame =
            JSON.stringify(inParams) === JSON.stringify(this.state.inParams)
        } catch (e) {}
        try {
          inParamsSame =
            JSON.stringify(outParams) === JSON.stringify(this.state.outParams)
        } catch (e) {}
        if (!inParamsSame || !outParamsSame) {
          obj.inParams = inParams
          obj.outParams = outParams
          treeActions.changeNodeProps({
            nodeId: nodeId,
            props: {
              inParams: inParams,
              outParams: outParams
            },
            addRecord: false
          })
          this.reloadAction()
        }
      }
    }
    return obj
  }

  reloadAction() {
    newEventStores.reloadAction(this.props.nodeId)
  }

  onAddParam(type) {
    let obj = { paramWarning: undefined }
    let params = undefined
    switch (type) {
      case 'in':
        params = this.state.inParams
        params.push({
          name: 'param' + (this.state.inParams.length + 1)
        })
        obj.inParams = params
        break
      case 'out':
        params = this.state.outParams
        params.push('param' + (this.state.outParams.length + 1))
        obj.outParams = params
        break
    }
    this.setState(obj, () => {
      delete obj.paramWarning
      this.modifySharedData(type, params)
      treeActions.changeNodeProps({
        nodeId: this.props.nodeId,
        props: obj
      })
      this.reloadAction()
    })
  }

  onDeleteParam(index, type) {
    let obj = { paramWarning: undefined }
    let params = undefined
    switch (type) {
      case 'in':
        params = this.state.inParams
        params.splice(index, 1)
        obj.inParams = params
        break
      case 'out':
        params = this.state.outParams
        params.splice(index, 1)
        obj.outParams = params
        break
    }
    this.setState(obj, () => {
      delete obj.paramWarning
      this.modifySharedData(type, params)
      treeActions.changeNodeProps({
        nodeId: this.props.nodeId,
        props: obj
      })
      this.reloadAction()
    })
  }

  onChangeType(index, type, paramType, applyChange, e) {
    let value = e === 'undefined' ? undefined : e
    this.onChangeParam(index, type, paramType, applyChange, value)
  }

  onChangeParam(index, type, paramType, applyChange, e) {
    let value = e && e.target ? e.target.value : e
    let obj = {}
    let params = undefined
    // 处理有问题字段
    if (type === 'out' || (type === 'in' && paramType === 'name')) {
      if (applyChange && !isValidParamName(value)) {
        let errorValue = value
        if (value !== 'detail') {
          // outParam为detail时,不对其强行修改,只给出提示.其余情况将值改为paramX
          value = 'param' + (index + 1)
        }
        obj.paramWarning = {
          error: 'paramError',
          type: type,
          index,
          value: errorValue
        }
      } else {
        obj.paramWarning = undefined
      }
    }
    switch (type) {
      case 'in':
        params = this.state.inParams
        params[index][paramType] = value
        if (paramType === 'required' && !value) {
          // 为false不需要保存
          delete params[index][paramType]
        }
        obj.inParams = params
        break
      case 'out':
        params = this.state.outParams
        params[index] = value
        obj.outParams = params
        break
    }
    let nodeId = this.props.nodeId
    this.setState(obj, () => {
      if (applyChange) {
        delete obj.paramWarning
        this.modifySharedData(type, params)
        treeActions.changeNodeProps({
          nodeId: nodeId,
          props: obj
        })
        if (type === 'out' || (type === 'in' && paramType === 'name')) {
          this.reloadAction()
        }
      }
    })
  }

  saveCase(done) {
    let nodeId = this.props.nodeId
    let node = getEventNodeById(nodeId)
    if (node && nodeIsNormalService(node.type) && node.uis && node.uis.new) {
      saveCaseBeforeActions({
        success: () => {
          done && done()
        },
        fail: () => {
          uiActions.toggleLoadingBar({ show: false })
        }
      })
    } else {
      done && done()
    }
  }

  onChangeShared(value) {
    if (value) {
      // 添加共享
      uiActions.toggleLoadingBar({
        show: true,
        title: i18n.t('LoadingBar.addSharedServiceTitle'),
        content: i18n.t('LoadingBar.addSharedServiceContent'),
        progress: 100,
        type: 'dbLoading'
      })
      this.saveCase(() => {
        let nodeId = this.props.nodeId
        let node = getEventNodeById(nodeId)
        this.addShareData({
          name: (node && node.uis && node.uis.name) || undefined
        }).then(result => {
          uiActions.toggleLoadingBar({ show: false })
          // 添加后操作
          if (result && result.isSuccess) {
            this.sharedServiceInfo = {
              id: result.id,
              uri: result.uri,
              gid: result.gid
            }
            this.setState({
              isShared: value,
              sharedTitle: result.title,
              sharedDesc: result.desc
            })
            if (result.gid) {
              serviceActions.clearGroupCache({ gid: result.gid })
            }
          } else if (result.err) {
            message.error(result.err)
          }
        })
      })
    } else {
      // 删除共享
      uiActions.toggleLoadingBar({
        show: true,
        title: i18n.t('LoadingBar.delSharedServiceTitle'),
        content: i18n.t('LoadingBar.delSharedServiceContent'),
        progress: 100,
        type: 'dbLoading'
      })
      this.deleteShareData().then(result => {
        uiActions.toggleLoadingBar({ show: false })
        // 删除后操作
        if (result) {
          this.sharedServiceInfo = undefined
          this.setState({
            isShared: value,
            sharedTitle: '',
            sharedDesc: ''
          })
        }
      })
    }
  }

  onChangeSharedInfo(type, applyChange, e) {
    let value = e && e.target ? e.target.value : e
    let obj = undefined
    if (type === 'title') {
      obj = {
        sharedTitle: value
      }
    } else if (type === 'desc') {
      obj = {
        sharedDesc: value
      }
    }
    if (obj) {
      this.setState(obj, () => {
        if (applyChange) {
          this.modifySharedData(type, value)
        }
      })
    }
  }

  getSharedData(final) {
    let result = {
      fileName: this.state.sharedTitle,
      content: {
        desc: this.state.sharedDesc,
        inParams: this.state.inParams,
        outParams: this.state.outParams
      }
    }
    if (final) {
      result.content = JSON.stringify(result.content)
    }
    return result
  }

  addShareData({ name }) {
    return new Promise(resolve => {
      let { nid, gid } = treeStore.curCaseInfo
      let uri = this.props.nodeId + '-' + nid
      let data = this.getSharedData()
      data.fileName = name || i18n.t('EventView.jenga_extra.defaultServiceName')
      data.content.desc = i18n.t('EventView.jenga_extra.defaultServiceDesc')
      data.scope = gid ? 1 : 2
      data.uri = uri
      if (gid) {
        data.gid = gid
      }
      // json化
      data.content = JSON.stringify(data.content)
      if (this.sharedServiceInfo) {
        resolve({ isSuccess: false })
        return
      }
      // 添加发送请求
      serviceStore.addSharedService({ data }).then(result => {
        if (result && result.isSuccess && result.data) {
          let id = result.data.id
          let title = result.data.filename
          let desc = ''
          try {
            let params = JSON.parse(result.data.content)
            desc = params.desc
          } catch (e) {}
          resolve({ isSuccess: true, id, uri, gid, title, desc })
        } else {
          resolve({ isSuccess: false, err: result.err })
        }
      })
    })
  }

  modifySharedData(type, value) {
    if (!this.sharedServiceInfo) {
      return
    }
    // content形如：{desc: xxx, inParams: xxx, outParams: xxx}
    let data = this.getSharedData()
    switch (type) {
      case 'title':
        data.fileName = value
        break
      case 'desc':
        data.content.desc = value
        break
      case 'in':
        data.content.inParams = value
        break
      case 'out':
        data.content.outParams = value
        break
    }
    // json化
    data.content = JSON.stringify(data.content)
    let { uri, gid, id } = this.sharedServiceInfo
    data.uri = uri
    if (gid) {
      data.gid = gid
    }
    // 修改发送请求
    serviceStore.modifySharedService({ id, data })
  }

  deleteShareData() {
    return new Promise(resolve => {
      if (!this.sharedServiceInfo) {
        resolve(false)
        return
      }
      // 发送删除请求
      let { uri, gid, id } = this.sharedServiceInfo
      let data = {
        uri: uri
      }
      if (gid) {
        data.gid = gid
      }
      serviceStore.delSharedService({ id, data }).then(result => {
        resolve(result)
      })
    })
  }

  getInParams() {
    let inParams = []
    let node = getEventNodeById(this.props.nodeId)
    if (node) {
      inParams = node.props.inParams || inParams
    }
    return inParams
  }

  getOutParams() {
    let outParams = []
    let node = getEventNodeById(this.props.nodeId)
    if (node) {
      outParams = node.props.outParams || outParams
    }
    return outParams
  }

  getInParamsName() {
    let title = ''
    let node = getEventNodeById(this.props.nodeId)
    if (node && widgetStore.widget[node.type]) {
      let prop = widgetStore.widget[node.type].map.propsMap['inParams']
      title = prop.locale ? prop.locale[i18n.language] : prop.name
    }
    return title + '：'
  }

  getOutParamsName() {
    let title = ''
    let node = getEventNodeById(this.props.nodeId)
    if (node && widgetStore.widget[node.type]) {
      let prop = widgetStore.widget[node.type].map.propsMap['outParams']
      title = prop.locale ? prop.locale[i18n.language] : prop.name
    }
    return title + '：'
  }

  getTitleName(range) {
    let title = ''
    let node = getEventNodeById(this.props.nodeId)
    if (node && widgetStore.widget[node.type]) {
      let map = widgetStore.widget[node.type].map
      title = map.locale ? map.locale[i18n.language] : map.name
    }
    let text = range ? 'range' : 'define'
    return title ? title + i18n.t('EventView.jenga_extra.' + text) : title
  }

  genAddButton(type) {
    return (
      <button
        className="btn-clear btn-add-param"
        onClick={this.onAddParam.bind(this, type)}
      >
        <div className="icon">
          <span className="horizon" />
          <span className="vertical" />
        </div>
      </button>
    )
  }

  getInParamsCom(param, index, type) {
    let length = this.state.inParams.length
    let extraBtn = length - 1 === index ? this.genAddButton(type) : null
    return (
      <div
        className={cls('param-item f--hlc', {
          'param-item-bottom': length > 0 && index !== length - 1
        })}
        key={index}
      >
        <div className="item-name">
          {i18n.t('EventView.jenga_extra.param') + (index + 1)}
        </div>
        <div className="item-input-wrap f--hlc flex-1">
          <div className="item-name first inner-name">
            {i18n.t('EventView.jenga_extra.name')}
          </div>
          <input
            className="service-input"
            value={param.name}
            onChange={this.onChangeParam.bind(this, index, type, 'name', false)}
            onBlur={this.onChangeParam.bind(this, index, type, 'name', true)}
          />
          <div className="item-name inner-name">
            {i18n.t('EventView.jenga_extra.type')}
          </div>
          <Select
            onChange={this.onChangeType.bind(this, index, type, 'type', true)}
            value={param.type}
            placeholder={i18n.t('FunctionView.Any')}
            className="prop-select prop-pair-select"
            dropdownClassName="prop-select-dropdown"
          >
            {this.types.map((item, index) => {
              return (
                <Option key={index} value={item.value} title={item.name}>
                  {item.name}
                </Option>
              )
            })}
          </Select>
          <div className="item-name inner-name">
            {i18n.t('EventView.jenga_extra.required')}
          </div>
          <Switch
            className="service-switch"
            checked={param.required || false}
            onChange={this.onChangeParam.bind(
              this,
              index,
              type,
              'required',
              true
            )}
          />
          <div className="f--hlc default-wrap">
            <div className="item-name inner-name">
              {i18n.t('EventView.jenga_extra.default')}
            </div>
            <input
              className="service-input"
              value={param.default || ''}
              placeholder={i18n.t('EventView.jenga_extra.debug-placeholder')}
              onChange={this.onChangeParam.bind(
                this,
                index,
                type,
                'default',
                false
              )}
              onBlur={this.onChangeParam.bind(
                this,
                index,
                type,
                'default',
                true
              )}
            />
          </div>
          <button
            className="btn-clear btn-delete-param"
            onClick={this.onDeleteParam.bind(this, index, type)}
          />
        </div>
        {extraBtn}
      </div>
    )
  }

  genInput(value, index, type) {
    let length =
      type === 'in' ? this.state.inParams.length : this.state.outParams.length
    let extraBtn = length - 1 === index ? this.genAddButton(type) : null
    return (
      <div
        className={cls('param-item f--hlc', {
          'param-item-left': index % 3 !== 0,
          'param-item-bottom': length > 3 && index < length - (length % 3 || 3)
        })}
        key={index}
      >
        <div className="item-name">
          {i18n.t('EventView.jenga_extra.param') + (index + 1)}
        </div>
        <div className="item-input-wrap f--hlc flex-1">
          <input
            value={value}
            onChange={this.onChangeParam.bind(
              this,
              index,
              type,
              undefined,
              false
            )}
            onBlur={this.onChangeParam.bind(this, index, type, undefined, true)}
          />
          <button
            className="btn-clear btn-delete-param"
            onClick={this.onDeleteParam.bind(this, index, type)}
          />
        </div>
        {extraBtn}
      </div>
    )
  }

  genError(type) {
    return this.state.paramWarning && this.state.paramWarning.type === type ? (
      <div className="param-warning f--hlc">
        {'* ' +
          i18n.t('EventView.jenga_extra.param') +
          (this.state.paramWarning.index + 1) +
          i18n.t('EventView.jenga_extra.setAs') +
          '"' +
          this.state.paramWarning.value +
          '"' +
          '，' +
          i18n.t('EventView.jenga_extra.' + this.state.paramWarning.error)}
      </div>
    ) : null
  }

  getSharedConfig() {
    let { allowConfigShare, isShared, sharedTitle, sharedDesc } = this.state
    return allowConfigShare ? (
      <div
        className={cls('shared-service-config', isShared ? 'f--h' : 'f--hlc')}
      >
        <div className="title">
          {treeStore.curCaseInfo.gid
            ? i18n.t('EventView.jenga_extra.shared_group_service')
            : treeStore.curCaseInfo.eid
            ? i18n.t('EventView.jenga_extra.shared_enterprise_service')
            : i18n.t('EventView.jenga_extra.shared_service')}
          {isShared && (
            <span className="shared-service-tips">
              {i18n.t('EventView.jenga_extra.shared-service-tips')}
            </span>
          )}
        </div>
        {allowConfigShare === 'loading' ? (
          <div>{i18n.t('EventView.jenga_extra.loading-data')}</div>
        ) : allowConfigShare === 'reload' ? (
          <button
            className="btn-clear btn-reload"
            onClick={this.loadSharedService}
          >
            {i18n.t('EventView.jenga_extra.reload-data')}
          </button>
        ) : (
          <div className="f--h">
            <Switch
              checked={isShared}
              onChange={this.onChangeShared}
              className="shared-service-switch"
            />
            {isShared ? (
              <>
                <div className="shared-item f--h">
                  <div className="item-title">
                    {i18n.t('EventView.jenga_extra.service-title')}
                  </div>
                  <input
                    value={sharedTitle}
                    onChange={this.onChangeSharedInfo.bind(
                      this,
                      'title',
                      false
                    )}
                    onBlur={this.onChangeSharedInfo.bind(this, 'title', true)}
                  />
                </div>
                <div className="shared-item f--h">
                  <div className="item-title">
                    {i18n.t('EventView.jenga_extra.service-desc')}
                  </div>
                  <textarea
                    value={sharedDesc}
                    onChange={this.onChangeSharedInfo.bind(this, 'desc', false)}
                    onBlur={this.onChangeSharedInfo.bind(this, 'desc', true)}
                  />
                </div>
              </>
            ) : null}
          </div>
        )}
      </div>
    ) : null
  }

  render() {
    return (
      <div className="jenga-node-params jenga-normal-service-params">
        {this.getSharedConfig()}
        <div
          className={cls(
            'params params-in no-border',
            this.state.inParams.length > 0 ? 'f--h' : 'f--hlc'
          )}
        >
          <div
            className={cls(
              'params-title params-in-title',
              this.state.inParams.length > 1
                ? 'params-title-top f--h'
                : 'f--hlc'
            )}
          >
            {this.getInParamsName()}
          </div>
          <div>
            <div className="main-wrap f--hlc">
              {this.state.inParams.length === 0
                ? this.genAddButton('in')
                : this.state.inParams.map((param, index) => {
                    return this.getInParamsCom(param, index, 'in')
                  })}
            </div>
            {this.genError('in')}
          </div>
        </div>
        <div
          className={cls(
            'params params-out',
            this.state.outParams.length > 0 ? 'f--h' : 'f--hlc'
          )}
        >
          <div
            className={cls(
              'params-title params-out-title',
              this.state.outParams.length > 3
                ? 'params-title-top f--h'
                : 'f--hlc'
            )}
          >
            {this.getOutParamsName()}
          </div>
          <div>
            <div className="main-wrap f--hlc">
              {this.state.outParams.length === 0
                ? this.genAddButton('out')
                : this.state.outParams.map((param, index) => {
                    return this.genInput(param, index, 'out')
                  })}
            </div>
            {this.genError('out')}
          </div>
        </div>
        <div className="params-title params-def-title params-service-title f--hlc">
          <div className="flex-1">{this.getTitleName()}</div>
        </div>
      </div>
    )
  }
}
