package com.hfkj.service.impl;

import com.hfkj.channel.weixin.WxOrderService;
import com.hfkj.channel.weixin.entity.OrderRefundModel;
import com.hfkj.channel.weixin.entity.OrderType;
import com.hfkj.common.exception.ErrorCode;
import com.hfkj.common.exception.ErrorHelp;
import com.hfkj.common.exception.SysCode;
import com.hfkj.common.utils.DateUtil;
import com.hfkj.common.utils.IDGenerator;
import com.hfkj.dao.BsDeviceMapper;
import com.hfkj.dao.BsDeviceOrderMapper;
import com.hfkj.entity.*;
import com.hfkj.model.UserInfoModel;
import com.hfkj.service.*;
import com.hfkj.sysenum.*;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.swing.*;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @className: BsDeviceOrderServiceImpl
 * @author: HuRui
 * @date: 2022/12/28
 **/
@Service("deviceOrderService")
public class BsDeviceOrderServiceImpl implements BsDeviceOrderService {

    @Resource
    private BsDeviceOrderMapper deviceOrderMapper;

    @Resource
    private BsDeviceService deviceService;

    @Resource
    private BsDevicePriceService devicePriceService;

    @Resource
    private BsDeviceOrderAssignService deviceOrderAssignService;

    @Resource
    private BsPayQrCodeService payQrCodeService;

    @Resource
    private CommonService commonService;

    @Override
    public BsDeviceOrder editData(BsDeviceOrder deviceOrder) {
        if (deviceOrder.getId() == null) {
            deviceOrder.setCreateTime(new Date());
            deviceOrderMapper.insert(deviceOrder);
        } else {
            deviceOrderMapper.updateByPrimaryKey(deviceOrder);
        }
        return deviceOrder;
    }

    @Override
    public BsDeviceOrder createOrder(DeviceOrderTypeEnum orderType, DeviceTypeEnum deviceType, Integer deviceNum, UserInfoModel userInfoModel) throws Exception {
        DevicePriceTypeEnum devicePriceType = DevicePriceTypeEnum.getDataByNumber(orderType.getNumber());
        if (devicePriceType == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未知设备价格");
        }
        // 设备金额
        BigDecimal devicePrice = devicePriceService.getPriceByType(devicePriceType,deviceType);
        BsDeviceOrder deviceOrder = new BsDeviceOrder();
        deviceOrder.setOrderType(orderType.getNumber());
        deviceOrder.setDeviceType(deviceType.getNumber());
        deviceOrder.setOrderNo(DateUtil.date2String(new Date(),"yyyyMMddHHmmss") + IDGenerator.nextId(5));
        deviceOrder.setDeviceNum(deviceNum);
        deviceOrder.setOrderPrice(devicePrice.multiply(new BigDecimal(deviceOrder.getDeviceNum().toString())));
        deviceOrder.setPayPrice(devicePrice.multiply(new BigDecimal(deviceOrder.getDeviceNum().toString())));
        deviceOrder.setStatus(DeviceOrderStatusEnum.status1.getNumber());
        deviceOrder.setCreateTime(new Date());
        deviceOrder.setSalesmanId(userInfoModel.getStore().getSalesmanId());
        deviceOrder.setSalesmanName(userInfoModel.getStore().getSalesmanName());
        deviceOrder.setStoreId(userInfoModel.getStore().getId());
        deviceOrder.setStoreName(userInfoModel.getStore().getName());
        deviceOrder.setMerId(userInfoModel.getStore().getMerId());
        deviceOrder.setMerName(userInfoModel.getStore().getMerName());
        deviceOrder.setAgentId(userInfoModel.getStore().getAgentId());
        deviceOrder.setAgentName(userInfoModel.getStore().getAgentName());
        deviceOrder.setCompanyId(userInfoModel.getStore().getCompanyId());
        deviceOrder.setCompanyName(userInfoModel.getStore().getCompanyName());

        if (deviceOrder.getPayPrice().equals(new BigDecimal("0"))) {
            deviceOrder.setPayType(0);
            deviceOrder.setPayTime(new Date());
            deviceOrder.setStatus(DeviceOrderStatusEnum.status2.getNumber());
        }
        return editData(deviceOrder);
    }

    @Override
    public void paySuccess(BsDeviceOrder order) {
        editData(order);
    }

    @Override
    @Transactional(propagation= Propagation.REQUIRES_NEW,rollbackFor= {RuntimeException.class})
    public void assignOrder(String orderNo, List<String> deviceNoList) {
        // 设备订单
        BsDeviceOrder order = getDetailOrder(orderNo);
        if (order == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未知的订单号");
        }
        if (!order.getStatus().equals(DeviceOrderStatusEnum.status2.getNumber())) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "订单不处于已支付状态");
        }
        if (!order.getDeviceNum().equals(deviceNoList.size())) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "分配数量和订单需求不一致");
        }
        order.setStatus(DeviceOrderStatusEnum.status3.getNumber());
        editData(order);

        if (order.getDeviceType().equals(DeviceTypeEnum.type1.getNumber())) {
            List<BsDevice> deviceList = new ArrayList<>();
            for (String deviceNo : deviceNoList) {
                // 查询设备
                BsDevice device = deviceService.getDetailByNo(deviceNo);
                if (device == null) {
                    throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未知的订单号");
                }
                if (!device.getDeviceType().equals(order.getDeviceType())) {
                    throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "设备编号："+device.getDeviceNo() + "无法分配，设备类型不匹配");
                }
                if (device.getStoreId() != null) {
                    throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "设备编号："+device.getDeviceNo() + "无法分配，已分配给" + device.getStoreName());
                }
                device.setSalesmanId(order.getSalesmanId());
                device.setSalesmanName(order.getSalesmanName());
                device.setMerId(order.getMerId());
                device.setMerName(order.getMerName());
                device.setStoreId(order.getStoreId());
                device.setStoreName(order.getStoreName());
                device.setBindTime(new Date());
                device.setBindStatus(true);
                deviceList.add(device);

                BsDeviceOrderAssign orderAssign = new BsDeviceOrderAssign();
                orderAssign.setOrderId(order.getId());
                orderAssign.setOrderNo(order.getOrderNo());
                orderAssign.setOrderType(order.getOrderType());
                orderAssign.setDeviceType(order.getDeviceType());
                orderAssign.setPaySerialNo(order.getPaySerialNo());
                orderAssign.setDeviceId(device.getId());
                orderAssign.setDeviceNo(device.getDeviceNo());
                orderAssign.setDevicePrice(order.getOrderPrice().divide(new BigDecimal(order.getDeviceNum().toString())));
                orderAssign.setDeviceActualPrice(order.getPayPrice().divide(new BigDecimal(order.getDeviceNum().toString())));
                orderAssign.setStatus(1);
                orderAssign.setCompanyId(order.getId());
                orderAssign.setCompanyName(order.getCompanyName());
                orderAssign.setAgentId(order.getAgentId());
                orderAssign.setAgentName(order.getAgentName());
                orderAssign.setSalesmanId(order.getSalesmanId());
                orderAssign.setSalesmanName(order.getSalesmanName());
                orderAssign.setMerId(order.getMerId());
                orderAssign.setMerName(order.getMerName());
                orderAssign.setStoreId(order.getStoreId());
                orderAssign.setStoreName(order.getStoreName());
                deviceOrderAssignService.editData(orderAssign);
            }

            for (BsDevice device : deviceList) {
                deviceService.editDevice(device);
            }
        } else if (order.getDeviceType().equals(DeviceTypeEnum.type2.getNumber())) {
            // 查询分配数量
            List<BsDeviceOrderAssign> assignList = deviceOrderAssignService.getAssignListByOrderNo(order.getOrderNo());
            // 已分配数量 + 待分配数量
            int countNum = assignList.size() + deviceNoList.size();
            if (countNum > order.getDeviceNum().intValue()) {
                throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "无法分配，超过订单需求数量");
            }

            for (String serialNumber : deviceNoList) {
                // 查询支付码
                BsPayQrCode payQrCode = payQrCodeService.getDetailBySN(serialNumber);
                if (payQrCode == null) {
                    throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未知的支付码编号：" + serialNumber);
                }
                if (payQrCode.getStoreBindTime() != null) {
                    throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "支付码编号：" + serialNumber + "已被绑定");
                }
                if (!payQrCode.getStatus().equals(PayQrCodeStatusEnum.status1.getNumber())) {
                    throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "支付码状态错误");
                }
                payQrCode.setSalesmanId(order.getSalesmanId());
                payQrCode.setSalesmanName(order.getSalesmanName());
                payQrCode.setStoreId(order.getStoreId());
                payQrCode.setStoreName(order.getStoreName());
                payQrCode.setStoreBindTime(new Date());
                payQrCode.setMerId(order.getMerId());
                payQrCode.setMerName(order.getMerName());
                payQrCodeService.editData(payQrCode, null);

                BsDeviceOrderAssign orderAssign = new BsDeviceOrderAssign();
                orderAssign.setOrderId(order.getId());
                orderAssign.setOrderNo(order.getOrderNo());
                orderAssign.setOrderType(order.getOrderType());
                orderAssign.setDeviceType(order.getDeviceType());
                orderAssign.setPaySerialNo(order.getPaySerialNo());
                orderAssign.setDeviceId(payQrCode.getId());
                orderAssign.setDeviceNo(payQrCode.getSerialNumber());
                orderAssign.setDevicePrice(order.getOrderPrice().divide(new BigDecimal(order.getDeviceNum().toString())));
                orderAssign.setDeviceActualPrice(order.getPayPrice().divide(new BigDecimal(order.getDeviceNum().toString())));
                orderAssign.setStatus(1);
                orderAssign.setCompanyId(order.getId());
                orderAssign.setCompanyName(order.getCompanyName());
                orderAssign.setAgentId(order.getAgentId());
                orderAssign.setAgentName(order.getAgentName());
                orderAssign.setSalesmanId(order.getSalesmanId());
                orderAssign.setSalesmanName(order.getSalesmanName());
                orderAssign.setMerId(order.getMerId());
                orderAssign.setMerName(order.getMerName());
                orderAssign.setStoreId(order.getStoreId());
                orderAssign.setStoreName(order.getStoreName());
                deviceOrderAssignService.editData(orderAssign);
            }
        }
    }

    @Override
    @Transactional(propagation= Propagation.REQUIRES_NEW,rollbackFor= {RuntimeException.class})
    public void replaceDevice(Long deviceOrderAssignId, String newDeviceNo) {
        BsDeviceOrderAssign orderAssign = deviceOrderAssignService.getDetailById(deviceOrderAssignId);
        if (orderAssign == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.REQ_PARAMS_ERROR, "");
        }
        if (!orderAssign.getStatus().equals(1)) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.STATUS_ERROR, "");
        }
        if (orderAssign.getDeviceType().equals(1)) {
            // 旧设备
            BsDevice oldDevice = deviceService.getDetailByNo(orderAssign.getDeviceNo());
            if (oldDevice == null) {
                throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未找到的旧设备号");
            }
            oldDevice.setMerId(null);
            oldDevice.setMerName(null);
            oldDevice.setStoreId(null);
            oldDevice.setStoreName(null);
            oldDevice.setBindStatus(false);
            oldDevice.setBindTime(null);
            deviceService.editDevice(oldDevice);

            // 新设备
            BsDevice newDevice = deviceService.getDetailByNo(newDeviceNo);
            if (newDevice == null) {
                throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未知的新设备号");
            }
            newDevice.setMerId(orderAssign.getMerId());
            newDevice.setMerName(orderAssign.getMerName());
            newDevice.setStoreId(orderAssign.getStoreId());
            newDevice.setStoreName(orderAssign.getStoreName());
            newDevice.setBindStatus(true);
            newDevice.setBindTime(new Date());
            deviceService.editDevice(newDevice);

            orderAssign.setDeviceId(newDevice.getId());
            orderAssign.setDeviceNo(newDevice.getDeviceNo());
            deviceOrderAssignService.editData(orderAssign);

        } else if (orderAssign.getDeviceType().equals(2)) {

        }
    }

    @Override
    @Transactional(propagation= Propagation.REQUIRES_NEW,rollbackFor= {RuntimeException.class})
    public void orderRefund(String orderNo) throws Exception {
        // 查询订单
        BsDeviceOrder order = getDetailOrder(orderNo);
        if (order == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未知的订单号");
        }
        if (!order.getStatus().equals(DeviceOrderStatusEnum.status2.getNumber())) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "状态不处于已支付，无法退款");
        }
        if (order.getPayType().equals(0)) {

        } else if (order.getPayType().equals(1)) {
            // 退款
            OrderRefundModel refund = WxOrderService.orderToRefund(order.getEntryPlatformMerNo(), order.getPaySerialNo(), order.getPayPrice(), order.getPayPrice());
            if(!refund.getResult_code().equals("SUCCESS")) {
                throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "退款失败！" + refund.getErr_code_des());
            }
        }

        order.setStatus(DeviceOrderStatusEnum.status4.getNumber());
        order.setRefundTime(new Date());
        editData(order);
    }

    @Override
    @Transactional(propagation= Propagation.REQUIRES_NEW,rollbackFor= {RuntimeException.class})
    public void deviceRefund(Long deviceOrderAssignId) throws Exception {
        // 设备分配订单
        BsDeviceOrderAssign deviceOrder = deviceOrderAssignService.getDetailById(deviceOrderAssignId);
        if (deviceOrder == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.REQ_PARAMS_ERROR, "");
        }
        if (!deviceOrder.getStatus().equals(1)) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.STATUS_ERROR, "");
        }
        if (deviceOrder.getDeviceType().equals(DeviceTypeEnum.type1.getNumber()) && deviceOrder.getOrderType().equals(DeviceOrderTypeEnum.type1.getNumber())) {
            // 退款条件
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未满足退款条件,暂时无法退款");

        } else if (deviceOrder.getOrderType().equals(DeviceOrderTypeEnum.type2.getNumber())) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "购买设备订单无法退款");
        }

        // 查询订单
        BsDeviceOrder order = getDetailOrder(deviceOrder.getOrderNo());
        if (order == null) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "未知的订单号");
        }
        if (order.getStatus().equals(DeviceOrderStatusEnum.status2.getNumber())) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "状态不处于已支付，无法退款");
        }

        // 退款
        OrderRefundModel refund = WxOrderService.orderToRefund(order.getEntryPlatformMerNo(), order.getPaySerialNo(), order.getPayPrice(), deviceOrder.getDeviceActualPrice());
        if (!refund.getResult_code().equals("SUCCESS")) {
            throw ErrorHelp.genException(SysCode.System, ErrorCode.COMMON_ERROR, "退款失败！" + refund.getErr_code_des());
        }
        deviceOrder.setStatus(3);
        deviceOrder.setRefundTime(new Date());
        deviceOrder.setRefundOrderNo(refund.getOut_refund_no());
        deviceOrderAssignService.editData(deviceOrder);

        // 查询是否已全部退款
        List<BsDeviceOrderAssign> list = deviceOrderAssignService.getAssignListByOrderNo(order.getOrderNo());
        Integer refundSize = list.stream().filter(o -> o.getStatus().equals(3)).collect(Collectors.toList()).size();
        if (order.getDeviceNum().equals(refundSize)) {
            order.setStatus(DeviceOrderStatusEnum.status4.getNumber());
            order.setRefundTime(new Date());
            editData(order);
        }

    }

    @Override
    public BsDeviceOrder getDetailOrder(String orderNo) {
        BsDeviceOrderExample example = new BsDeviceOrderExample();
        example.createCriteria().andOrderNoEqualTo(orderNo).andStatusNotEqualTo(0);
        List<BsDeviceOrder> list = deviceOrderMapper.selectByExample(example);
        if (list.size() > 0) {
            return list.get(0);
        }
        return null;
    }

    @Override
    public List<BsDeviceOrder> getOrderList(Map<String, Object> param) {
        BsDeviceOrderExample example = new BsDeviceOrderExample();
        BsDeviceOrderExample.Criteria criteria = example.createCriteria()
                                                .andStatusNotEqualTo(0);

        if (MapUtils.getInteger(param, "orderType") != null) {
            criteria.andOrderTypeEqualTo(MapUtils.getInteger(param, "orderType"));
        }

        if (MapUtils.getInteger(param, "deviceType") != null) {
            criteria.andDeviceTypeEqualTo(MapUtils.getInteger(param, "deviceType"));
        }

        if (StringUtils.isNotBlank(MapUtils.getString(param, "orderNo"))) {
            criteria.andOrderNoLike("%"+MapUtils.getString(param, "orderNo")+"%");
        }

        if (StringUtils.isNotBlank(MapUtils.getString(param, "paySerialNo"))) {
            criteria.andOrderNoLike("%"+MapUtils.getString(param, "paySerialNo")+"%");
        }

        if (StringUtils.isNotBlank(MapUtils.getString(param, "status"))) {
            List<Integer> list = new ArrayList<>();
            String[] statusArray = MapUtils.getString(param, "status").split(",");
            for (String i : statusArray) {
                list.add(Integer.parseInt(i));
            }
            criteria.andStatusIn(list);
        }

        if (MapUtils.getLong(param, "companyId") != null) {
            criteria.andCompanyIdEqualTo(MapUtils.getLong(param, "companyId"));
        }

        if (StringUtils.isNotBlank(MapUtils.getString(param, "companyName"))) {
            criteria.andCompanyNameLike("%"+MapUtils.getString(param, "companyName")+"%");
        }

        if (MapUtils.getLong(param, "agentId") != null) {
            criteria.andAgentIdEqualTo(MapUtils.getLong(param, "agentId"));
        }

        if (StringUtils.isNotBlank(MapUtils.getString(param, "agentName"))) {
            criteria.andAgentNameLike("%"+MapUtils.getString(param, "agentName")+"%");
        }

        if (MapUtils.getLong(param, "salesmanId") != null) {
            criteria.andSalesmanIdEqualTo(MapUtils.getLong(param, "salesmanId"));
        }

        if (StringUtils.isNotBlank(MapUtils.getString(param, "salesmanName"))) {
            criteria.andSalesmanNameLike("%"+MapUtils.getString(param, "salesmanName")+"%");
        }

        if (MapUtils.getLong(param, "merId") != null) {
            criteria.andMerIdEqualTo(MapUtils.getLong(param, "merId"));
        }

        if (StringUtils.isNotBlank(MapUtils.getString(param, "merName"))) {
            criteria.andMerNameLike("%"+MapUtils.getString(param, "merName")+"%");
        }

        if (MapUtils.getLong(param, "storeId") != null) {
            criteria.andStoreIdEqualTo(MapUtils.getLong(param, "storeId"));
        }

        if (StringUtils.isNotBlank(MapUtils.getString(param, "storeName"))) {
            criteria.andStoreNameLike("%"+MapUtils.getString(param, "storeName")+"%");
        }

        example.setOrderByClause("create_time desc");
        return deviceOrderMapper.selectByExample(example);
    }
}
