import React from 'react';
import RN, {DeviceEventEmitter, Image, View} from 'react-native';
import AsyncStorage from '@react-native-community/async-storage';
import {connect} from 'react-redux';
import {debounce} from 'throttle-debounce';
import KeyEvent from 'react-native-keyevent';
import Icon from 'react-native-vector-icons/Ionicons';
import NumberModal from '../components/NumberModal';
import Modal from '../components/Modal';
import {font} from '../utils/common';
import Touch from '../components/Touch';
import ModalStyles from '../components/Modal/styles';
import Speech from '../utils/Speech';
import Toast from '../components/Toast';
import NP from '../utils/np';
import {total} from '../utils/validity';
import RedPacketModal from '../components/RedPacketModal';

window.RN = RN;
window.Toast = Toast;
window.Speech = Speech;

const mStyles = {
  ...ModalStyles,
  innerContainer: {
    ...ModalStyles.innerContainer,
    width: 777,
  },
  header: {
    ...ModalStyles.header,
    fontSize: font.title,
  },
};

const clearTime = 300; // 五分钟自动清空购物车
const paidTime = 30; // 支付完成等待时间 30s
const delay = 1500; // 扫码后延迟时间

const wait = t => new Promise(resolve => setTimeout(resolve, t));

const CounterMixins = ComposeComponent => {
  class Mixins extends ComposeComponent {
    static displayName = 'CounterMixins';

    state = {
      goodsArr: [],
      preventRevert: false,
      modalS: false,
      current: 1,
      preventMsg: '',
      caseUp: false,
      voiceModal: false,
      title: '',
      dot: false,
      luckyVisible: false,
    };

    componentWillMount = async () => {
      const qrHost = await AsyncStorage.getItem('QRHOST');
      await this.setState({qrHost});
    };

    componentDidMount = async () => {
      window.scan = this.submitBarcode;
      window.clear = this.clearList;
      this.goodsMap = {}; // 缓存商品数据
      this.barcode = ''; // 记录条形码
      this.totalNum = 0; // 总件数
      this.weight = 0;
      this.clearListInter = setInterval(() => {
        window.count++;
        if (window.count === clearTime) {
          this.clearList();
          window.count = window.defaultCount;
        }
      }, 1000);
      DeviceEventEmitter.addListener('onSpeechStart', () => (this.busy = true));
      DeviceEventEmitter.addListener(
        'onSpeechFinish',
        () => (this.busy = false),
      );
      DeviceEventEmitter.addListener('onError', () => (this.busy = false));
      const handleScan = this.submitBarcode;
      // if you want to react to keyUp
      KeyEvent.onKeyUpListener(async e => {
        const {keyCode, pressedKey} = e;
        if (keyCode === 66) {
          // 回车事件
          await handleScan();
          this.barcode = '';
        } else if (keyCode >= 7 && keyCode <= 16) {
          this.barcode += keyCode - 7;
        } else if (keyCode >= 29 && keyCode <= 54) {
          this.barcode += pressedKey;
        }
      });
      this.listen();
    };

    componentWillUnmount = () => {
      clearInterval(this.clearListInter);
      clearInterval(this.payInter);
      clearTimeout(this.paidTimeout);
      KeyEvent.removeKeyUpListener();
    };

    setDelay = debounce(delay, true, () => {
      this.isDelay = true;
      setTimeout(() => {
        this.isDelay = false;
      }, delay);
    });

    listen = async () => {
      while (!window.socket) {
        await wait(1000);
      }
      if (window.socket.hasListeners('counterOrder')) {
        window.socket.removeAllListeners('counterOrder');
      }
      if (window.socket.hasListeners('cmdOperate')) {
        window.socket.removeAllListeners('cmdOperate');
      }
      window.socket.on('cmdOperate', this.command.bind(this));
      window.socket.on(
        'counterOrder',
        ({type, msg, sid, token, payType, orderId}) => {
          let totalPrice = this.totalPrice;
          let totalCount = this.totalCount;
          if (type === 'waiting') {
            // 客户端等待，响应购物车列表
            this.token = token;
            const {ids, noBarcode} = this.getGoods();
            window.socket.emit(
              'counterGoods',
              sid,
              JSON.stringify(ids),
              totalPrice,
              totalCount,
              payType,
              JSON.stringify(noBarcode),
            );
          } else if (type === 'fail') {
            // 下单失败
            Speech.speak(msg);
          } else if (type === 'paying') {
            // 下单成功，等待用户支付
            let count = 0;
            this.props.dispatch({
              // 扫码付款步骤
              type: 'app/step',
              step: 2,
            });
            clearInterval(this.payInter); // 清除定时查询订单
            this.payInter = setInterval(async () => {
              count++;
              if (count >= 30) {
                // 一分钟，超时关闭付款
                this.props.dispatch({
                  // 返回商品扫码步骤
                  type: 'app/step',
                  step: 1,
                });
                clearInterval(this.payInter);
                this.setState({voiceModal: false});
              }
            }, 2000);
            this.setState({voiceModal: true, voiceTitle: msg});
            Speech.speak(msg);
          } else if (type === 'paid') {
            if (orderId) {
              let count = 0;
              this.props.dispatch({
                // 扫码付款步骤
                type: 'app/step',
                step: 2,
              });
              clearInterval(this.payInter); // 清除定时查询订单
              this.payInter = setInterval(async () => {
                if (!this.state.voiceModal) {
                  clearInterval(this.payInter);
                }
                count++;
                const order = await this.props.dispatch({
                  type: 'goods/status',
                  orderId, // 订单号,
                });
                if (order.code === 1 && order.data === 1) {
                  this.successPay();
                  clearInterval(this.payInter); // 清除定时查询订单
                  this.isPaid = true; // 支付成功，暂停检测秤的重量
                  this.paidTimeout = setTimeout(() => {
                    this.isPaid = false;
                  }, paidTime * 1000);
                  setTimeout(() => {
                    this.props.dispatch({
                      // 返回商品扫码步骤
                      type: 'app/step',
                      step: 1,
                    });
                    this.setState({voiceModal: false});
                  }, 1200);
                }
                if (count >= 20) {
                  // 一分钟，超时关闭付款
                  this.props.dispatch({
                    // 返回商品扫码步骤
                    type: 'app/step',
                    step: 1,
                  });
                  clearInterval(this.payInter);
                  this.setState({voiceModal: false});
                }
              }, 3000);
            } else {
              this.props.dispatch({
                // 购物完成步骤
                type: 'app/step',
                step: 3,
              });
              this.clearList();
              this.setState({voiceModal: true, voiceTitle: msg});
              Speech.speak(msg);
              clearInterval(this.payInter); // 清除定时查询订单
              this.isPaid = true; // 支付成功，暂停检测重力感应器的重量
              this.paidTimeout = setTimeout(() => {
                this.isPaid = false;
              }, paidTime * 1000);
              setTimeout(() => {
                this.props.dispatch({
                  // 返回商品扫码步骤
                  type: 'app/step',
                  step: 1,
                });
                this.setState({voiceModal: false});
              }, 1200);
            }
          }
        },
      );
    };

    // 运营端远程命令
    command = ({cmd}) => {
      try {
        eval(cmd);
      } catch (e) {
        console.warn(e.message);
      }
    };

    // 锁定授权设置
    lock = lock => {
      if (!window.auth) {
        return '门店未授权无法锁定';
      }
      this.props.dispatch({
        type: 'app/lock',
        lock,
      });
      if (lock) {
        return '门店设置已锁定';
      }
      return '门店设置已解锁';
    };

    successPay = () => {
      const msg = '付款成功，祝您生活愉快~';
      this.props.dispatch({
        // 购物完成步骤
        type: 'app/step',
        step: 3,
      });
      this.clearList();
      this.setState({voiceModal: true, voiceTitle: msg});
      Speech.speak(msg);
      this.onLucky();
    };

    // 付款成功，若达到领取红包的金额则弹出领取红包的弹窗
    onLucky = async () => {
      // 支付成功，用户完成付款
      let {dispatch} = this.props;
      let {code: codeLucky, data: dataLucky} = await dispatch({
        type: 'lucky/getLucky',
        orderId: this.orderId,
      });
      if (codeLucky === 1) {
        this.setState({
          luckyVisible: true,
          amount: dataLucky.amount,
        });
        setTimeout(() => {
          this.setState({
            luckyVisible: false,
          });
        }, 10000);
      }
    };

    speak = (msg, showModal, duration = 3000) => {
      if (!this.busy) {
        Speech.speak(msg);
      }
      if (showModal) {
        this.setState({voiceModal: true, voiceTitle: msg});
        setTimeout(() => {
          this.setState({voiceModal: false});
        }, duration);
      }
    };

    dropUp = () => {
      let {current} = this.state;
      if (current > 1) {
        this.setDelay();
        this.setState({
          current: --current,
        });
      }
    };

    dropDown = goodsLength => {
      let {current} = this.state;
      if (current < goodsLength) {
        this.setDelay();
        this.setState({
          current: ++current,
        });
      }
    };

    numRemove = (num, index) => {
      if (num > 1) {
        this.setDelay();
        let gaArr = this.state.goodsArr;
        gaArr[index].num = Number(num) - 1;
        this.setState({
          goodsArr: gaArr,
        });
      }
      this.setState({
        focus: true,
      });
    };

    numChange = index => {
      this.handleScan = this.submitGoodNum;
      this.numIndex = index;
      this.setState({
        modalS: true,
        title: '修改数量',
      });
    };

    numAdd = (num, index) => {
      this.setDelay();
      let gaArr = this.state.goodsArr;
      if (gaArr[index].category === '特价') {
        Toast.info('特价商品每人限购一次哦', 2);
      } else {
        gaArr[index].num = Number(num) + 1;
        this.errGood = gaArr[index];
        this.errGood.index = index;
        this.setState({
          goodsArr: gaArr,
        });
      }
    };

    removeIndex = index => {
      this.setDelay();
      let goodsArr = [].concat(this.state.goodsArr);
      goodsArr.splice(index, 1);
      this.setState({
        goodsArr,
      });
    };

    submitGoodNum = async num => {
      this.setDelay();
      let gaArr = this.state.goodsArr;
      if (gaArr[this.numIndex].category === '特价') {
        Toast.info('特价商品每人限购一次哦', 2);
      } else {
        gaArr[this.numIndex].num = Number(num);
        this.errGood = gaArr[this.numIndex];
        this.errGood.index = this.numIndex;
        this.setState({
          goodsArr: gaArr,
        });
      }
    };

    submitBarcode = async barcode => {
      this.errGood = null;
      if (!window.auth) {
        const msg = '系统未授权，无法查询商品';
        this.setState({voiceModal: true, voiceTitle: msg});
        Speech.speak(msg);
        clearTimeout(this.noAuthTimeout);
        this.noAuthTimeout = setTimeout(() => {
          this.setState({voiceModal: false});
        }, 3000);
        return;
      }
      barcode = barcode || this.barcode;
      if (await this.barcodepay(barcode)) {
        return;
      }
      window.count = window.defaultCount;
      if (barcode) {
        const goods = this.goodsMap[barcode];
        if (!goods) {
          Toast.loading('正在查询商品');
        }
        this.setDelay();
        let {goodsArr} = this.state;
        let {data} = goods
          ? {data: {code: 1, data: goods}}
          : await this.props.dispatch({
              type: 'goods/getGoods',
              barcode,
            });
        if (!data) {
          return;
        }
        if (data.code < 0) {
          this.barcode = '';
          this.speak(data.msg);
          return;
        }
        let stopSpecial = false;
        if (data.data.category === '特价') {
          for (let i = 0; i < goodsArr.length; i++) {
            if (goodsArr[i].name === data.data.name) {
              stopSpecial = true;
              break;
            }
          }
        }
        let price = Number(data.data.price || data.data.prePrice);
        if (data.code === 1 && price > 0 && !stopSpecial) {
          if (!data.data.num) {
            data.data.numChange = true;
          } // 称重计价不可修改数量
          this.goodsMap[barcode] = data.data;
          let dataReal = data.data;
          dataReal.num = data.data.num || 1;
          goodsArr.push({...dataReal});
          const current = Math.ceil(goodsArr.length / window.pageSize);
          this.setState({
            current,
            goodsArr,
            modalS: false,
          });
          Toast.hide();
        } else if (data.code === 1 && price <= 0) {
          Toast.info('商品价格异常，请联系客服人员处理', 2);
        } else if (data.code === 1 && stopSpecial) {
          Toast.info('特价商品每人限购一次哦', 2);
        } else if (data.code === 2) {
          Toast.fail(data.data, 1.5);
        }
      }
    };

    submitCodeless = async price => {
      if (!total.test(price)) {
        Toast.info('商品价格的小数点只能输入两位', 2);
      } else if (Number(NP.round(price, 2).toFixed(2)) <= 0) {
        Toast.info('商品价格必须要大于0', 2);
      } else {
        const {goodsArr} = this.state;
        const good = {
          barcode: '000000',
          name: '无码商品',
          // unit: 1,
          num: 1,
          // price: NP.round(price, 2).toFixed(2),
          prePrice: NP.round(price, 2).toFixed(2),
          numChange: false,
        };
        goodsArr.push({...good});
        const current = Math.ceil(goodsArr.length / window.pageSize);
        this.setState({
          current,
          goodsArr,
          modalS: false,
          dot: false,
        });
        Toast.hide();
      }
    };

    getGoods = () => {
      const {goodsArr} = this.state;
      const ids = {};
      const noBarcode = [];
      goodsArr.map(({barcode, num, prePrice, name}) => {
        if (barcode !== '000000') {
          //非无码商品
          if (!ids[barcode]) {
            ids[barcode] = num;
          } else {
            ids[barcode] += num;
          }
        } else {
          noBarcode.push({
            name,
            barcode,
            price: 0,
            purPrice: 0,
            prePrice,
            num,
            weight: 0,
          });
        }
      });
      return {ids, noBarcode};
    };

    // 付款码支付
    barcodepay = async (code, facepay, openid) => {
      if (this.barcodeBusy) {
        return true;
      }
      const isWxpay = code.toString().match(/1[0-5]\d{16}/);
      const isAlipay = code.toString().match(/^(2[5-9]|30)\d{14,22}$/);
      if (!isWxpay && !isAlipay) {
        return false;
      }
      this.barcodeBusy = true;
      let successPay = false;
      const {ids, noBarcode} = this.getGoods();
      const res = await this.props.dispatch({
        type: 'goods/barcodepay',
        ids,
        code,
        facepay,
        noBarcode,
        openid,
      });
      if (res.code !== 1) {
        await this.setState({voiceModal: true, voiceTitle: res.msg});
        Speech.speak(res.msg);
      }
      if (res.code === 1) {
        // 付款成功
        this.orderId = res.data.orderId;
        if (res.data.users) {
          this.barcodeUser = res.data;
          await this.selectUserModal();
        }
        if (res.data.alipayUserId) {
          // 没有匹配到支付宝用户
          const voiceTitle =
            '为了正常出店，首次使用支付宝付款码，请用进店微信扫描屏幕二维码';
          // this.orderId = res.data.orderId;
          this.alipayUserId = res.data.alipayUserId;
          Speech.speak(voiceTitle);
          this.setState({voiceTitle});
        } else {
          this.successPay();
          successPay = true;
          await wait(1200);
          // await wait(res.data.timeout);
        }
      } else if (res.code === 2) {
        // 等待付款
        for (let i = 0; i < 20; i++) {
          await wait(3000);
          if (!this.state.voiceModal) {
            break;
          }
          const status = await this.props.dispatch({
            type: 'goods/status',
            orderId: res.data.orderId, // 订单号,
          });
          if (status.code === 1 && status.data === 1) {
            this.successPay();
            successPay = true;
            await wait(1200);
            break;
          }
        }
      } else if (res.code === 3) {
        // 付款失败
        await wait(res.data.timeout);
      } else {
        await wait(1200);
      }
      await this.setState({voiceModal: false});
      this.barcodeBusy = false;
      if (successPay) {
        return 'SUCCESS';
      }
      return true;
    };

    selectUserModal = () =>
      new Promise(async resolve => {
        this.barcodeResolve = resolve;
        const {users} = this.barcodeUser;
        const msg = '请选择您的微信账号或手机号码';
        await this.setState({users, usersModal: true, voiceTitle: msg});
        Speech.speak(msg);
        this.barcodeTimeout = setTimeout(() => {
          this.setState({usersModal: false});
          resolve();
        }, 30000);
      });

    // 选择付款码对应用户
    selectUser = userId => {
      const {alipayUserId, orderId} = this.barcodeUser;
      this.props.dispatch({
        type: 'goods/barcodeUser',
        userId,
        alipayUserId,
        orderId,
      });
      this.setState({usersModal: false});
      clearTimeout(this.barcodeTimeout);
      if (this.barcodeResolve) {
        this.barcodeResolve();
      }
    };

    handleBarcode = () => {
      this.handleScan = this.submitBarcode;
      this.setState({
        modalS: true,
        title: '录入条码',
        dot: false,
      });
    };

    handleCodeless = () => {
      this.handleScan = this.submitCodeless;
      this.setState({
        modalS: true,
        title: '无码商品',
        dot: true,
      });
    };

    clearList = () => {
      this.setDelay();
      this.goodsMap = {};
      this.setState({
        goodsArr: [],
      });
    };

    pushBag = index => {
      let {goods} = this.props;
      this.submitBarcode(goods.bags[index].barcode);
    };

    onCloseLucky = () => {
      this.setState({
        luckyVisible: false,
      });
    };

    onReceiveLucky = async () => {
      const {data} = await this.props.dispatch({
        type: 'lucky/receiveLucky',
        orderId: this.orderId,
      });
      Toast.success(data.msg);
    };

    render = () => {
      let {voiceModal, voiceTitle, title, luckyVisible, amount} = this.state;
      return (
        <View style={{flex: 1}}>
          <NumberModal
            title={title}
            onClose={() => this.setState({modalS: false, dot: false})}
            visible={this.state.modalS}
            onSubmit={this.handleScan}
            dot={this.state.dot}
          />
          <RedPacketModal
            luckyVisible={luckyVisible}
            amount={amount}
            orderId={this.orderId}
            onReceiveLucky={this.onReceiveLucky}
            onCloseLucky={this.onCloseLucky}
          />
          <Modal
            maskClosable
            styles={mStyles}
            visible={voiceModal}
            transparent
            title={voiceTitle}
            onClose={() => this.setState({voiceModal: false})}>
            <View style={{justifyContent: 'center', alignItems: 'center'}}>
              <CloseButton onClose={() => this.setState({voiceModal: false})} />
              <Image source={require('../assets/voice.gif')} />
            </View>
          </Modal>
          <ComposeComponent
            {...this.props}
            {...this.state}
            pushBag={this.pushBag}
            handleBarcode={this.handleBarcode}
            barcodepay={this.barcodepay}
            handleCodeless={this.handleCodeless}
            clearList={this.clearList}
            numAdd={this.numAdd}
            numRemove={this.numRemove}
            numChange={this.numChange}
            removeIndex={this.removeIndex}
            dropUp={this.dropUp}
            dropDown={this.dropDown}
            speak={this.speak}
          />
        </View>
      );
    };
  }

  return connect(({goods, admin}) => ({goods, admin}))(Mixins);
};

const CloseButton = ({onClose, style}) => {
  return (
    <Touch
      style={{position: 'absolute', top: -70, right: -5, ...style}}
      onPress={onClose}
      feedback={false}>
      <Icon size={40} name="ios-close-circle-outline" />
    </Touch>
  );
};

export default CounterMixins;
