<template>
  <el-card>
    <div
      slot="header"
      class="card-title">
      <span>订单明细</span>
      <!-- 仅测试环境方便调试用 -->
      <!-- <div v-if="['demo'].includes(scenicName)">
        原价{{ orderPrice }}元 ->铭投山庄预计优惠价：{{ mt_computedFinalPrice }}元
      </div> -->
      <el-link
        type="primary"
        @click="$emit('clear')">
        清空订单
      </el-link>
    </div>
    <div>
      <div class="payChannel-wrap">
        <label class="text">支付方式：</label>
        <el-radio-group
          fill="#379143"
          class="tags-btn"
          @change="$localStore.set('retail_payment',$event)"
          v-model="payChannel"
          border>
          <el-radio
            border
            v-for="val in payChannelOptions"
            :key="val"
            :value="val"
            :label="val"></el-radio>
        </el-radio-group>
      </div>
      <div
        v-if="['铭投山庄','大陈岛景区','demo'].includes(scenicName)"
        class="btn-wrap">
        <div>
          <!-- 铭投山庄定制的手动优惠 -->
          <span class="item">
            手动优惠金额<Tip
              msg="输入手动降价金额后按回车。"
              style="margin-left: 0!important;"></Tip>：
            <el-input-number
              :min="0"
              :precision="2"
              :controls="false"
              v-model.number="mt_manaulCutMoney"></el-input-number>
            （相当于{{ this.$NP.round(mt_orderDiscount,3) }} 折）
          </span>
          <span
            class="item">
            <el-select
              v-model="mt_intdisplayDiscount"
              placeholder="整数折扣（非必选）">
              <el-option
                v-for="i in 10"
                :key="i"
                :label="i + '折'"
                :value="i"></el-option>
            </el-select>
            <Tip
              msg="可用于选择整数折扣（非必选）"
              style="margin-left: 0!important;"></Tip>
          </span>
        </div>
      </div>
      <div class="btn-wrap">
        <div>
          <span class="item">实付金额：
            <el-input-number
              :min="0"
              :precision="2"
              :controls="false"
              v-model.number="actualMoney"></el-input-number>
          </span>
          <span class="item">备注：
            <el-input
              clearable
              v-model="remark"
              style="width:200px"></el-input>
          </span>
          <span class="item">图片备注：
            <el-button
              type="primary"
              size="small"
              icon="el-icon-edit"
              @click="showUploadImgDialog"
            >
              编辑查看
            </el-button>
          </span>
        </div>

        <el-button
          type="primary"
          class="warnBtn item"
          :disabled="value.length===0"
          @click="handleConfirm">
          确认出票
        </el-button>
      </div>

      <div class="btn-wrap">
        <span class="item price">总数：<b>{{ totalCount }}</b> 张</span>
        <div v-if="(['铭投山庄','大陈岛景区','demo'].includes(scenicName)) && (orderPrice !== 0) && (mt_manaulCutMoney > 0)">
          <!-- 铭投山庄优惠定制，仅开启手动优惠时生效 -->
          <span class="item price">总价：<del><b>{{ orderPrice }}</b></del> &nbsp; <b>{{ mt_computedFinalPrice }}</b> 元</span>
          <span class="item price">{{ '手动降价' }}：<b>{{ this.$NP.round(orderPrice - mt_computedFinalPrice, 2) }}</b> 元</span>
          <span class="item price">{{ mt_payBack>0?'找零':'还需支付' }}：<b>{{ Math.abs(mt_payBack) }}</b> 元</span>
        </div>
        <div v-else>
          <!-- 其他通用景区 -->
          <span class="item price">总价：<b>{{ orderPrice }}</b> 元</span>
          <span class="item price">{{ payBack>0?'找零':'还需支付' }}：<b>{{ Math.abs(payBack) }}</b> 元</span>
        </div>
        <span class="item">
          <PrintSmallTicketCheckbox v-model="autoPrintSmallTicket"></PrintSmallTicketCheckbox>

          <el-checkbox
            v-model="autoPrint"
            style="margin:10px"
            @change="handleAutoPrintChange"
          >
            自动打印
          </el-checkbox>
        </span>
      </div>
    </div>

    <el-table
      border
      :data="value">
      <el-table-column
        prop="ticketName"
        label="票种名称"
        width="180">
      </el-table-column>
      <el-table-column label="游玩日期">
        <template slot-scope="scope">
          {{ scope.row.payDateBegin | formatDate }}
        </template>
      </el-table-column>
      <el-table-column
        prop="count"
        label="数量">
      </el-table-column>
      <el-table-column
        prop="price"
        label="单价">
      </el-table-column>
      <el-table-column
        prop="total"
        label="小计">
      </el-table-column>
      <el-table-column
        label="操作"
        width="140">
        <template slot-scope="scope">
          <el-button
            @click="handleDelete(scope.row)"
            type="text">
            删除
          </el-button>
          <el-button
            @click="showTouristList(scope.row)"
            type="text">
            门票列表
          </el-button>
        </template>
      </el-table-column>
    </el-table>

    <!-- 铭投山庄和demo的定制打折，此为铭投山庄定制版 (scenicName==='铭投山庄' || scenicName==='demo') -->
    <!-- order-price传打折后的最终价格，order-items传修改后的value（根据最终价格敲定），注意不要传computed里的函数，那会导致订单明细不显示 this.mt_figureout_finalPrice(this.value, this.mt_mannualCutMoney)-->
    <Confirm
      v-if="(scenicName === 'demo' || scenicName==='铭投山庄' || scenicName === '大陈岛景区')"
      :remark="remark"
      :tickets="mt_tickets"
      :order-items="mt_calc_value()"
      :form-data="formData"
      :order-price="this.mt_figureout_finalPrice(this.value, this.mt_manaulCutMoney)"
      :total-count="totalCount"
      :pay-channel="payChannel"
      @complete="handleComplete"
      ref="confirm"></Confirm>
    <!-- 对于非铭投山庄的其他景点，应用原有的参数(下面这个不能改) -->
    <Confirm
      v-else
      :remark="remark"
      :tickets="tickets"
      :order-items="value"
      :form-data="formData"
      :order-price="orderPrice"
      :total-count="totalCount"
      :pay-channel="payChannel"
      @complete="handleComplete"
      ref="confirm"></Confirm>
    <!-- 图片备注 -->
    <UploadImgList
      :picture-remarks="pictureRemarks"
      :update-remarks="updateRemarks"
      ref="uploadImgDialog">
    </UploadImgList>

    <!-- 游客列表 -->
    <TouristList
      :check-face="formData.checkWay === 4"
      :check-id="formData.checkWay === 3"
      :check-ticket-no="formData.checkWay === 5"
      :tourist-list="touristList"
      :update-tourist="updateTourist"
      ref="touristList"></TouristList>
  </el-card>
</template>

<script>
import mixin from './mixin'
import { randomString } from '@/utils'
import Confirm from './Confirm'
import PrintSmallTicketCheckbox from '../common/PrintSmallTicketCheckbox'
import UploadImgList from '../common/uploadImgList'
import orderItemMixin from '../common/orderItemMixin'
import Tip from '@/components/Tip'
export default {
  mixins: [mixin, orderItemMixin],
  props: {
    value: {
      type: Array,
      default: () => []
    }
  },
  components: {
    Confirm,
    PrintSmallTicketCheckbox,
    Tip,
    UploadImgList
  },
  computed: {
    payBack () {
      if (this.actualMoney === undefined) {
        return -this.orderPrice
      } else {
        return this.$NP.minus(this.actualMoney, this.orderPrice)
      }
    },
    mt_payBack () { // 铭投山庄定制手动打折时找零专用
      let p = this.mt_computedFinalPrice
      if (this.actualMoney === undefined) {
        return -p
      } else {
        return this.$NP.minus(this.actualMoney, p)
      }
    },
    totalCount () {
      return this.value.reduce((init, item) => {
        return init + item.count
      }, 0)
    },
    orderPrice () {
      return this.value.reduce((init, item) => {
        let price = this.$NP.times(item.count, item.price)
        return this.$NP.plus(init, price)
      }, 0)
    },
    scenicName () {
      return this.$localStore.get('scenicName') || this.$store.state.user.scenicName
    },
    mt_computedValue () {
    // 通过规定的最终打折后价格，去逆推凑出按比例降价后的order-items，也就是this.value，但为了兼容避免修改this.value
      let finalPrice = this.mt_figurout_finalPrice(this.value) // 不能使用computed里的finalPrice，那会导致订单出不来，而应使用methods里的函数
      return this.mt_applyDiscount(this.value, finalPrice)
    },
    mt_computedFinalPrice () {
      return this.mt_calc_finalPrice()
    },
    mt_tickets () {
      let val = this.mt_calc_value()
      return val.reduce((init, item) => {
        return init.concat(item.tickets)
      }, [])
    },
    tickets () {
      return this.value.reduce((init, item) => {
        return init.concat(item.tickets)
      }, [])
    }
  },
  data () {
    return {
      payChannel: '',
      actualMoney: 0,
      remark: '',
      formData: {},
      pictureRemarks: [{
        idKey: randomString(),
        url: '',
        remark: ''
      }],
      discountStrategyName: '',
      mt_manaulCutMoney: 0, // 手动优惠的钱数（即降了多少）
      mt_orderDiscount: 10, // 铭投山庄总的订单折扣，可以决定手动优惠的钱数
      mt_intdisplayDiscount: 10, // 铭投可选的整数订单折扣（只能1到10）
      autoPrint: this.$localStore.get('autoPrint'),
      autoPrintSmallTicket: this.$localStore.get('autoPrintSmallTicket')
    }
  },
  methods: {
    // 根据最终价格，按比例逆推每张票的单价，去凑出设定的最终价格，来算order-items，也就是this.value
    mt_applyDiscount (value, finalPrice) {
      // 克隆this.value，避免直接修改原对象
      let newValue = JSON.parse(JSON.stringify(value))
      // 计算当前订单的总价
      let totalPrice = newValue.reduce((acc, cur) => acc + cur.total, 0)
      // 计算折扣比例
      // 注意，若卖0元票，会导致总价为0，计算折扣会出现除以0的异常，discountRate算成NAN，导致tickets里的每张price都是无效值
      let discountRate = (totalPrice === 0) ? 1 : this.$NP.divide(finalPrice, totalPrice) // finalPrice / totalPrice
      // 遍历每个票种
      for (let i = 0; i < newValue.length; i++) {
        let ticketType = newValue[i]
        // 更新ticketType的单价和总价
        ticketType.price = this.$NP.round(this.$NP.times(ticketType.price, discountRate), 2) // ticketType.price *= discountRate
        ticketType.total = this.$NP.round(this.$NP.times(ticketType.price, ticketType.count), 2) // ticketType.total = ticketType.price * ticketType.count
        // 遍历该票种的每张票
        for (let j = 0; j < ticketType.tickets.length; j++) {
          let ticket = ticketType.tickets[j]
          // 记录每张票的原先价格
          ticket.original_price = ticket.price
          // 降低每张票的价格
          ticket.price = this.$NP.round(this.$NP.times(ticket.price, discountRate), 2) // ticket.price *= discountRate
        }
      }
      // 在上面大致凑出新的票价之后，需要处理一下因为保留两位小数引起的误差
      // 目前假设测试数据是 总价格230元=10元票*3张+100元票*2张，经过此函数处理后，变成 150元=7.83元票*3张+78.26元*2张
      // 但150元并不与（7.83元票*3张+78.26元*2张）这个严格相等，可能差0.01元
      // mt_adjustPrice函数把相差的钱数再第一张票里凑出来，也就是通过微调第一张票的价格，使最终价格150元与所有票的价格加起来严格相等
      let finalValue = this.mt_adjustValue(newValue, finalPrice) // 这里传入我们修改后的newValue，adjustValue主要是修复一分钱的舍入误差
      return finalValue
    },
    // 微调第一张票的价格，弥补保留两位小数可能引起的一分钱误差
    mt_adjustValue (value, finalPrice) {
      // 克隆this.value，避免直接修改原对象
      let newValue = JSON.parse(JSON.stringify(value))
      let totalSum = this.$NP.round(newValue.reduce((acc, cur) => {
        return acc + cur.total
      }, 0), 2)
      let minorDiff = this.$NP.round(totalSum - finalPrice, 2) // 不保留两位的话，可能是0.00999，保留之后可能是0.01
      if (newValue && newValue[0] && newValue[0].price) {
        newValue[0].tickets[0].price = this.$NP.round(this.$NP.minus(newValue[0].tickets[0].price, minorDiff), 2)
        if (newValue[0].count < 2) {
          // 若第一个票的票种里票较多，不必修改该票种的价格
          newValue[0].price = this.$NP.round(this.$NP.minus(newValue[0].price, minorDiff), 2)
        }
        newValue[0].total = this.$NP.round(this.$NP.minus(newValue[0].total, minorDiff), 2)
      }
      console.log('舍入小差：', minorDiff, newValue)
      return newValue
    },
    mt_figureout_finalPrice (value, cutMoney) {
      let orderPrice = value.reduce((init, item) => {
        let price = this.$NP.times(item.count, item.price)
        return this.$NP.plus(init, price)
      }, 0) // computed里若直接用this.orderPrice()会不正常
      const ticket = {
        price: orderPrice
      }
      const handler = {
        get: function (target, prop) {
          // 如果是折扣价，返回手动打折后的价格（铭投山庄定制）
          if (prop === 'discountPrice') {
            return target.price - cutMoney > 0 ? target.price - cutMoney : 0 // 保证打折后价格为非负
            // 注意不能直接使用this.mt_manaulCutMoney，因为这个在变动；把本函数变成纯函数，通过传参获得手动降价的钱数，不会出现异常
          }
          return target[prop]
        }
      }
      const ticketProxy = new Proxy(ticket, handler)
      // ticketProxy.price --打折后--> ticketProxy.discountPrice
      return this.$NP.round(ticketProxy.discountPrice, 2)
    },
    mt_calc_value () {
    // 通过规定的最终打折后价格，去逆推凑出按比例降价后的order-items，也就是this.value，但为了兼容避免修改this.value
      let finalPrice = this.mt_calc_finalPrice() // this.mt_figureout_finalPrice(this.value) // 不能使用computed里的finalPrice函数，那会导致订单出不来，而应使用methods里的函数
      let newValue = this.mt_applyDiscount(this.value, finalPrice)
      return newValue
    },
    mt_calc_finalPrice () {
      return this.mt_figureout_finalPrice(this.value, this.mt_manaulCutMoney)
    },
    mt_manual2discount (mt_manual_val) {
      console.log(this.mt_computedFinalPrice, mt_manual_val)
      if (mt_manual_val && this.mt_computedFinalPrice && mt_manual_val + this.mt_computedFinalPrice > 0) {
        this.mt_orderDiscount = this.mt_computedFinalPrice / (mt_manual_val + this.mt_computedFinalPrice) * 10
      } else if (mt_manual_val === 0) {
        this.mt_orderDiscount = 10 // 若手动优惠了0元，则重置为10折，主要用于重置遗留的数值。
      }
    },
    mt_discount2manual (mt_orderdis_val) {
      // 根据折扣去算手动优惠价格
      let p = this.orderPrice
      let disc = mt_orderdis_val * 0.1
      console.log('根据折扣去算手动优惠价格:', p - p * disc)
      this.mt_manaulCutMoney = p - p * disc
    },
    // 更新图片备注列表
    updateRemarks (data) {
      this.pictureRemarks = data
    },
    // 显示图片备注弹窗
    showUploadImgDialog () {
      this.$refs.uploadImgDialog.show()
    },
    changePayChannel (n) {
      if (this.confirmVisible) return

      let i = this.payChannelOptions.findIndex(channel => channel === this.payChannel)
      let l = this.payChannelOptions.length
      let j = (i - n + l) % l
      this.payChannel = this.payChannelOptions[j]
    },
    PageUp () {
      this.changePayChannel(1)
    },
    PageDown () {
      this.changePayChannel(-1)
    },
    handleDelete (item) {
      this.$confirm('确定删除吗?', '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        this.$message({
          type: 'success',
          message: '删除成功!'
        })
        const idx = this.value.findIndex(i => i.keyId === item.keyId)
        this.value.splice(idx, 1)
      })
    },
    handleAutoPrintChange (val) {
      this.$localStore.set('autoPrint', val)
    },
    handleComplete () {
      this.$emit('clear')
      this.remark = ''
      this.$localStore.get('defaultPayWay') && this.setPayWay()
      this.$parent.$parent.$refs.orderRecord.getOrderList()
    },
    setPayWay () {
      const payment = this.$localStore.get('defaultPayWay') || this.payChannelOptions[0]

      this.payChannel = this.payChannelOptions.indexOf(payment) < 0 ? this.payChannelOptions[0] : payment
    }
  },
  watch: {
    orderPrice (val) {
      // 其他没有打折功能的通用景区
      if (!['铭投山庄', '大陈岛景区', 'demo'].includes(this.scenicName)) {
        this.actualMoney = val
      }
    },
    // 铭投山庄打折时定制实付金额
    mt_computedFinalPrice (val) {
      if (['铭投山庄', '大陈岛景区', 'demo'].includes(this.scenicName)) {
        this.actualMoney = val
        /* 上一单打折付款完了之后，要在售票清单里没票时，重置手动降价的金额为0 */
        if (val === 0) {
          this.mt_manaulCutMoney = 0
        }
      }
    },
    mt_manaulCutMoney (val) {
      // 由手动优惠金额去修改订单总折扣
      this.mt_manual2discount(val)
    },
    mt_orderDiscount (val) {
      // 由订单总折扣去修改手动优惠金额
      this.mt_discount2manual(val)
      // 若这个相当于的折扣为整数，则去更新下拉框的整数折扣
      let isIntegerInRange = num => Number.isInteger(num) && num >= 1 && num <= 10
      if (isIntegerInRange(this.$NP.round(val, 3))) {
        this.mt_intdisplayDiscount = this.$NP.round(val, 3)
      } else {
        this.mt_intdisplayDiscount = '非整数折扣'
      }
    },
    totalCount (totalCount_val) {
      // 总数变了，也要相应去改折扣，比如手动优惠没变，但多加入了几张票使总价增加
      // 这里就不要改相当于的折扣了，而是通过手动优惠算出折扣
      this.mt_manual2discount(this.mt_manaulCutMoney)
    },
    mt_intdisplayDiscount (int_val) {
      let isIntegerInRange = num => Number.isInteger(num) && num >= 1 && num <= 10
      if (isIntegerInRange(int_val)) {
      // 只有是整数折时，才会通过折扣去更新手动优惠价格
        this.mt_discount2manual(int_val)
      }
    },
    payChannelOptions: {
      handler (val) {
        if (val.length) {
          this.setPayWay()
        }
      },
      immediate: true
    }
  },
  mounted () {
    this.payChannel = this.$localStore.get('defaultPayWay') || this.$localStore.get('retail_payment') || this.payChannelOptions[0]
  }
}
</script>

<style lang="scss" scoped>
.item {
  margin-left: 20px;
}
.price-info {
  padding: 10px 0;  text-align: right; background: #fff;
}
.btn-wrap {
  display: flex; width: 100%; margin-bottom: 10px; font-size: 14px; justify-content: space-between; align-items: center;

  .el-input {
    display: inline-block; width: 100px;
  }
}

</style>
