package com.gree.mall.manager.logic.order;

import cn.hutool.core.util.EnumUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.binarywang.wxpay.bean.profitsharing.ProfitSharingQueryResult;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.gree.mall.manager.bean.ExcelData;
import com.gree.mall.manager.bean.admin.AdminUserCom;
import com.gree.mall.manager.bean.order.OrderShareReportBean;
import com.gree.mall.manager.commonmapper.OrderShareReportMapper;
import com.gree.mall.manager.enums.*;
import com.gree.mall.manager.exception.RemoteServiceException;
import com.gree.mall.manager.logic.common.CommonLogic;
import com.gree.mall.manager.logic.common.WechatLogic;
import com.gree.mall.manager.plus.entity.OrderInfo;
import com.gree.mall.manager.plus.entity.OrderRefund;
import com.gree.mall.manager.plus.entity.OrderShare;
import com.gree.mall.manager.plus.entity.User;
import com.gree.mall.manager.plus.service.OrderInfoService;
import com.gree.mall.manager.plus.service.OrderRefundService;
import com.gree.mall.manager.plus.service.OrderShareService;
import com.gree.mall.manager.plus.service.UserService;
import com.gree.mall.manager.utils.DateUtils;
import com.gree.mall.manager.utils.excel.ExcelUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Slf4j
@RequiredArgsConstructor
public class OrderShareLogic {

    private final WechatLogic wechatLogic;

    private final CommonLogic commonLogic;
 
    private final OrderShareService orderShareService;

    private final UserService userService;

    private final OrderShareReportMapper orderShareReportMapper;

    private final OrderInfoService orderInfoService;

    private final OrderRefundService orderRefundService;


    public IPage<OrderShare> list(HttpServletRequest request,String userId, String websitId, String orderShareId, String orderId, String workUserName, String phone, String status,
                                  String startTime, String endTime, String startSettleTime, String endSettleTime, String position,
                                  String startPayTime,String endPayTime, String payType, Integer pageNo, Integer pageSize) {
        AdminUserCom adminUser = commonLogic.getAdminUser(request);
        log.info("结算管理:companyWechatId:{},adminWebsitIds:{}",JSONObject.toJSONString(adminUser.getAdminCompanyIds()),JSONObject.toJSONString(adminUser.getAdminWebsitIds()));
        IPage<OrderShare> page = orderShareService.lambdaQuery()
                .in(CollectionUtils.isNotEmpty(adminUser.getAdminCompanyIds()),OrderShare::getCompanyWechatId,adminUser.getAdminCompanyIds())
                .in(CollectionUtils.isNotEmpty(adminUser.getAdminWebsitIds()),OrderShare::getWebsitId,adminUser.getAdminWebsitIds())
                .eq(StringUtils.isNotEmpty(userId), OrderShare::getUserId, userId)
                .like(StringUtils.isNotEmpty(orderShareId), OrderShare::getOrderShareId, orderShareId)
                .like(StringUtils.isNotEmpty(orderId), OrderShare::getOrderId, orderId)
                .like(StringUtils.isNotEmpty(workUserName), OrderShare::getWorkUserName, workUserName)
                .like(StringUtils.isNotEmpty(phone), OrderShare::getPhone, phone)
                .eq(StringUtils.isNotEmpty(status), OrderShare::getStatus, status)
                .between(StringUtils.isNotEmpty(startTime) && StringUtils.isNotEmpty(endTime), OrderShare::getCreateTime, startTime, endTime)
                .between(StringUtils.isNotEmpty(startSettleTime) && StringUtils.isNotEmpty(endSettleTime), OrderShare::getSettleTime, startSettleTime, endSettleTime)
                .between(StringUtils.isNotEmpty(startPayTime) && StringUtils.isNotEmpty(endPayTime),OrderShare::getPayTime,startPayTime,endPayTime)
                .eq(org.apache.commons.lang3.StringUtils.isNotBlank(payType), OrderShare::getPayType, payType)
                .orderByDesc(OrderShare::getCreateTime)
                .page(new Page<>(pageNo, pageSize));
        return page;
    }


    public void export(HttpServletRequest request, HttpServletResponse response, String userId, String websitId, String orderShareId, String orderId,
                       String workUserName, String phone, String status, String startTime, String endTime, String startSettleTime, String endSettleTime,
                       String payType,
                       String position,String startPayTime,String endPayTime) throws Exception {
        List<OrderShare> list = list(request,userId, websitId, orderShareId, orderId, workUserName, phone, status, startTime, endTime,
                startSettleTime, endSettleTime, position,startPayTime,endPayTime, payType,1,-1).getRecords();
        String[] titles = {"序号","结算编号","订单类型", "订单编号", "店铺名称", "商品信息", "单价", "数量", "总金额",
                "商品佣金", "订单佣金","优惠金额","结算金额","平台优惠券名称", "交易单号",
                "售后服务", "下单账号", "下单时间", "支付时间", "支付方式", "佣金结算状态",
                "结算时间","分销员", "所属网点","商品佣金类型","订单状态", "职位",
                "买家备注", "收货人",
                "手机号", "收货地址", "物流公司", "物流单号", "发票类型", "发票抬头", "发票内容",
                "纳税人识别号", "名称", "公司注册地址", "公司注册电话", "开户银行", "银行账号", "收票人姓名",
                "收票人地址", "收票人手机", "收票人邮箱", "商户单号",
                "订单结算状态","支付时间", "支付方式", "备注"};
        ExcelData excelData = new ExcelData();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        if(CollectionUtils.isEmpty(list)){
            String fileName = String.format("结算导出_%s.xlsx", simpleDateFormat.format(new Date()));
            excelData.setTitles(Arrays.asList(titles));
            excelData.setName("结算订单");
            excelData.setRows(new ArrayList<>());
            ExcelUtils.exportExcel(request, response, fileName, excelData, -1, null);
            return;
        }

        List<String> orderIds = list.stream().map(OrderShare::getOrderId).collect(Collectors.toList());

        List<OrderShareReportBean> orderShareReportBeans = orderShareReportMapper.queryReport(orderIds);

        List<List<Object>> rows = new ArrayList<>();

        final String SHOP_NAME = "格匠商城";
        for (int i = 0; i < orderShareReportBeans.size(); i++) {
            OrderShareReportBean bean = orderShareReportBeans.get(i);
            List<Object> row = new ArrayList<>();
            row.add(i + 1);
            row.add(bean.getOrderShareId());
           // row.add(bean.getMainNumber());
            row.add(bean.getOrderId());
            row.add(SHOP_NAME);
         /*   row.add(bean.getGoodsName());
            row.add(bean.getPrice());
            row.add(bean.getNum());*/
            row.add(bean.getTotalPrice());

          //  row.add(bean.getShareAmount());//"商品佣金"
            row.add(bean.getAmount());//"订单佣金"
            row.add(bean.getDiscountAmount());//优惠金额
           // row.add(bean.getPayAmount().subtract(bean.getShareAmount()));//"结算金额"
            row.add(bean.getCouponName());//"平台优惠券名称"
            row.add(bean.getTransactionId());//"交易单号"

            row.add(bean.getOrderStatus().equals(OrderStatusEnum.REFUND.toString()) ? "退款关闭" : "无");
            row.add(bean.getUserId());
            row.add(bean.getCreateTime() == null ? "" : simpleDateFormat.format(bean.getCreateTime()));
            row.add(bean.getPayTime() == null ? "" : simpleDateFormat.format(bean.getPayTime()));
            row.add(bean.getPayType());


            row.add(Enum.valueOf(OrderShareStatusEnum.class, bean.getShareStatus().trim().toUpperCase()).getName());//"佣金结算状态"
            row.add(bean.getSettleTime() == null ? "" : simpleDateFormat.format(bean.getSettleTime()));//"结算时间"
            row.add(bean.getWorkUserName());//"分销员"
            row.add(bean.getWebsitName());//"所属网点"
            row.add("");//"商品佣金类型"
            row.add(Enum.valueOf(OrderStatusEnum.class, bean.getOrderStatus().trim().toUpperCase()).getName());//"订单状态"
            row.add(bean.getPosition());// "职位"

            row.add(bean.getRemark());
            row.add(bean.getReceUserName());
            row.add(bean.getRecePhone());
            row.add(bean.getAddress());
            row.add(bean.getName());
            row.add(bean.getLogisticsNo());

            row.add(bean.getType() == null || !bean.getType() ? "个人发票" : "公司发票");
            row.add(bean.getTaxName());
            row.add(bean.getContent());
            row.add(bean.getTaxNo());
            row.add(bean.getTaxName());

            row.add(bean.getRegisterAddress());
            row.add(bean.getRegisterPhone());
            row.add(bean.getBank());
            row.add(bean.getAccount());
            row.add(bean.getReceiverName());
            row.add(bean.getReceiverAddress());
            row.add(bean.getReceiverPhone());
            row.add(bean.getReceiverEmail());

            row.add("");
            row.add("");
            row.add(simpleDateFormat.format(bean.getPayTime()));
            row.add(bean.getPayType().equals(PayTypeEnum.UNIONPAY.getName()) ? PayTypeEnum.UNIONPAY.getName() : PayTypeEnum.WEIXIN.getName());
            row.add(bean.getRemark() == null ? "" : bean.getRemark());
            rows.add(row);
        }

        String fileName = String.format("结算导出_%s.xlsx", simpleDateFormat.format(new Date()));
        excelData.setTitles(Arrays.asList(titles));
        excelData.setName("结算订单");
        excelData.setRows(rows);
//        final int[] mergeRows = new int[]{1,2,7, 9, 10, 11, 12, 13, 14, 15, 16, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 34, 35, 36, 41, 42, 43, 44};
        ExcelUtils.exportExcel(request, response, fileName, excelData, -1, null);

    }


    public void export2(HttpServletRequest request, HttpServletResponse response, String userId, String websitId, String orderShareId, String orderId,
                        String workUserName, String phone, String status, String startTime, String endTime, String startSettleTime, String endSettleTime,
                        String position, String payType, String startPayTime, String endPayTime) throws Exception {

        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        String[] titles = {"序号", "商城名称", "结算编号", "订单号" , "订单佣金", "总价", "折扣金额", "实付金额", "运费", "订单状态", "退款标记", "下单用户账号",
                "下单时间", "支付方式", "支付时间", "买家备注", "收货人", "收货电话", "收货地址", "物流单号", "物流公司", "发票类型",
                "发票抬头", "发票内容", "订单发票纳税人识别号", "订单发票公司注册地址", "订单发票公司注册电话", "订单发票开户行", "订单发票开户账号", "订单发票接收邮箱", "订单发票接收手机号",
                "订单发票收件人", "订单发票收件地址", "优惠券名称", "订单交易号", "佣金结算状态", "分销员", "订单所属网点",
                "结算时间", "职位", "支付方式"};

        ExcelData excelData = new ExcelData();
        String fileName = String.format("结算导出_%s.xlsx", simpleDateFormat.format(new Date()));
        excelData.setTitles(Arrays.asList(titles));
        excelData.setName("结算订单");

        List<OrderShare> list = list(request, userId, websitId, orderShareId, orderId, workUserName, phone, status, startTime, endTime,
                startSettleTime, endSettleTime, position, startPayTime, endPayTime, payType,1, -1).getRecords();

        if (CollectionUtils.isEmpty(list)) {
            excelData.setRows(new ArrayList<>());
            ExcelUtils.exportExcel(request, response, fileName, excelData, -1, null);
            return;
        }
        //todo  延用原export()中的实现方案  如果出现太慢还是推荐在mybatis中设置条件
        List<String> orderShareIdList = list.stream().map(OrderShare::getOrderShareId).collect(Collectors.toList());

        List<OrderShareReportBean> orderShareReportBeans = orderShareReportMapper.queryReport2(orderShareIdList);

        List<List<Object>> rows = new ArrayList<>();
        for (int i = 0; i < orderShareReportBeans.size(); i++) {
            OrderShareReportBean bean = orderShareReportBeans.get(i);
            List<Object> row = new ArrayList<>();
            rows.add(row);

            row.add(i + 1);
            row.add(bean.getShopName());
            row.add(bean.getOrderShareId());
            row.add(bean.getOrderId());
            row.add(bean.getAmount());
            row.add(bean.getTotalPrice());
            row.add(bean.getDiscountAmount());
            row.add(bean.getPayAmount());
            row.add(bean.getFreight());
            row.add(Enum.valueOf(OrderStatusEnum.class, bean.getOrderStatus().trim().toUpperCase()).getName());
            row.add(StringUtils.isEmpty(bean.getRefundFlag())?"":RefundFlagEnum.valueOf(bean.getRefundFlag()).getName());
            row.add(bean.getUserId());

            row.add(bean.getCreateTime() == null ? "" : simpleDateFormat.format(bean.getCreateTime()));
            row.add(bean.getPayType());
            row.add(bean.getPayTime() == null ? "" : simpleDateFormat.format(bean.getPayTime()));
            row.add(bean.getRemark() == null ? "" : bean.getRemark());
            row.add(bean.getReceUserName());
            row.add(bean.getRecePhone());
            row.add(bean.getAddress());
            row.add(bean.getLogisticsNo());
            row.add(bean.getName());
            row.add(bean.getType() == null || !bean.getType() ? "个人发票" : "公司发票");

            row.add(bean.getTaxName());
            row.add(bean.getContent());
            row.add(bean.getTaxNo());
            row.add(bean.getRegisterAddress());
            row.add(bean.getRegisterPhone());
            row.add(bean.getBank());
            row.add(bean.getAccount());
            row.add(bean.getReceiverEmail());
            row.add(bean.getReceiverPhone());

            row.add(bean.getReceiverName());
            row.add(bean.getReceiverAddress());
            row.add(bean.getCouponName());
            row.add(bean.getTransactionId());
            row.add(Enum.valueOf(OrderShareStatusEnum.class, bean.getShareStatus().trim().toUpperCase()).getName());
            row.add(bean.getWorkUserName());
            row.add(bean.getWebsitName());

            row.add(bean.getSettleTime() == null ? "" : simpleDateFormat.format(bean.getSettleTime()));
            row.add(bean.getPosition());
            row.add(bean.getPayType().equals(PayTypeEnum.UNIONPAY.getName()) ? PayTypeEnum.UNIONPAY.getName() : PayTypeEnum.WEIXIN.getName());

        }
        excelData.setRows(rows);
        ExcelUtils.exportExcel(request, response, fileName, excelData, -1, null);

    }

    public void updateOrderStatus(String orderId, String orderStatus) {
        orderShareService.lambdaUpdate()
                .set(OrderShare::getOrderStatus, orderStatus)
                .set(orderStatus.equals(OrderStatusEnum.CLOSE.toString()), OrderShare::getStatus, OrderShareStatusEnum.CANCEL.toString())
                .ne(OrderShare::getStatus,OrderShareStatusEnum.OVER.toString())
                .eq(OrderShare::getOrderId, orderId)
                .update();
    }

    public void updateOrderShare(String orderId, String orderStatus) {
        orderShareService.lambdaUpdate()
                .eq(OrderShare::getOrderId, orderId)
                .set(OrderShare::getStatus, orderStatus)
                .set(OrderShare::getSettleTime, new Date())
                .set(OrderShare::getShareStatus, WXShareStatusEnum.PROCESSING.toString())
                .update();
    }

    public void remark(String orderShareId,String remark){
        OrderShare orderShare = orderShareService.getById(orderShareId);
        orderShare.setRemark(remark);
        orderShare.updateById();
    }

    /**
     * 师傅本月的结算数
     */
    public Integer getShareNum(String mobile){
        User user = userService.lambdaQuery().eq(User::getWorkPhone, mobile).last("limit 1").one();
        if(user == null){
            return 0;
        }
        Date startMonth = DateUtils.getStartMonth();
        Date endMonth = DateUtils.getEndMonth();
        Integer count = orderShareService.lambdaQuery()
                .eq(OrderShare::getOpenId, user.getOpenId())
                .ne(OrderShare::getStatus, OrderShareStatusEnum.CANCEL.toString())
                .between(OrderShare::getCreateTime, startMonth, endMonth)
                .count();
        return count;
    }

    /**
     * 确认分账
     * @param orderId
     * @throws RemoteServiceException
     */
    public void confirm(String orderId) throws RemoteServiceException {
        List<OrderShare> list = orderShareService.lambdaQuery()
                .eq(OrderShare::getOrderId, orderId)
                .eq(OrderShare::getStatus,OrderShareStatusEnum.ING.toString())
                .list();

        OrderInfo orderInfo = orderInfoService.getById(orderId);
        if (orderInfo == null || !orderInfo.getOrderStatus().equals(OrderStatusEnum.OVER.toString())) {
            throw new RemoteServiceException("订单不符合结算条件");
        }
        if(list.size() == 0){
            throw new RemoteServiceException("不存在未结算的信息");
        }
        try {
            if(StringUtils.isEmpty(orderInfo.getCompanyId())){
                return;
            }
            //查询是否存在未处理完成的售后单
            Integer count = orderRefundService.lambdaQuery()
                    .eq(OrderRefund::getOrderId,orderId)
                    .in(OrderRefund::getOrderStatus, "DSJCL", "DSJSH", "DMJCL").count();
            if(count > 0){
                throw new RemoteServiceException("订单"+orderId+"存在未完结的维权订单");
            }
            wechatLogic.shareAmount(orderId, orderInfo.getTransactionId(), list, orderInfo.getCompanyId());
            this.updateOrderShare(orderId, OrderShareStatusEnum.OVER.toString());

        } catch (WxPayException e) {
            log.error("异常结算", e);
            this.saveOrderShareRemark(orderId,OrderShareStatusEnum.EXCEPTION.toString(),"异常结算："+e.getErrCodeDes());
            throw new RemoteServiceException("转账支付失败");
        }
    }


    public Boolean confirmAuto(List<OrderShare> orderShares, OrderInfo orderInfo) {
        try {
            if (StringUtils.isEmpty(orderInfo.getCompanyId())) {
                return false;
            }

            wechatLogic.shareAmount(orderInfo.getOrderId(), orderInfo.getTransactionId(), orderShares, orderInfo.getCompanyId());
            this.updateOrderShare(orderInfo.getOrderId(), OrderShareStatusEnum.OVER.toString());
            return true;
        } catch (WxPayException e) {
            log.error("异常结算", e);
            this.saveOrderShareRemark(orderInfo.getOrderId(), OrderShareStatusEnum.EXCEPTION.toString(), "异常结算：" + e.getErrCodeDes());
            return false;
        }

    }

    /**
     * 用户总收益
     *
     * @param userId
     * @return
     */
    public BigDecimal totalAmount(String userId) {
        List<OrderShare> list = orderShareService.lambdaQuery().eq(OrderShare::getUserId, userId).list();
        return list.stream().map(OrderShare::getAmount).reduce(BigDecimal::add).orElse(new BigDecimal(0));
    }


    /**
     * 刷新分佣金额
     * @param orderId 订单号
     * @param totalShareAmount 总分佣金额
     * @param flag //1=非团购商品  2=团购商品
     */
    public void reloadAmount(String orderId, BigDecimal totalShareAmount,Integer flag) {
        OrderShare orderShare = orderShareService.lambdaQuery()
                .eq(OrderShare::getOrderId, orderId)
                .eq(OrderShare::getFlag,flag).one();
        if(orderShare == null){
            return;
        }
        if(orderShare.getStatus().equals(OrderShareStatusEnum.OVER.toString())){
            return;
        }
        if (totalShareAmount == null) {
            orderShare.setStatus(OrderShareStatusEnum.CANCEL.toString());
            orderShare.updateById();
            return;
        }
        //1=非团购商品  2=团购商品
        if (orderShare != null) {
            OrderInfo orderInfo = orderInfoService.getById(orderShare.getOrderId());
            orderInfo.setOrderId(orderShare.getOrderId());
            if (orderShare.getAmount().subtract(totalShareAmount).doubleValue() <= 0.01) {
                orderShare.setStatus(OrderShareStatusEnum.CANCEL.toString());
                orderInfo.setTotalShareAmount(BigDecimal.valueOf(0));
            } else {
                orderShare.setAmount(orderShare.getAmount().subtract(totalShareAmount));
                orderInfo.setTotalShareAmount(orderInfo.getTotalShareAmount().subtract(totalShareAmount));
            }
            orderShare.updateById();
            orderInfo.updateById();

        }
    }



    public List<OrderShare> getOrderShareList(String orderId){
        List<OrderShare> list = orderShareService.lambdaQuery().eq(OrderShare::getOrderId, orderId).list();
        return list;
    }


    /**
     * 记录失败原因
     */
    public void saveOrderShareRemark(String orderId,String orderShareStatus,String remark){
        orderShareService.lambdaUpdate()
                .set(OrderShare::getStatus,orderShareStatus)
                .set(OrderShare::getRemark,remark)
                .eq(OrderShare::getOrderId,orderId).update();
    }

    /**
     * 查询分账结果
     * @param share
     * @throws Exception
     */
    public void queryShareResult(OrderShare share) throws Exception {
        ProfitSharingQueryResult result = wechatLogic.profitSharingResult(share);
        if (Objects.isNull(result)) {
            orderShareService.lambdaUpdate()
                    .set(OrderShare::getShareFailReason, "缺少商户id")
                    .set(OrderShare::getStatus, WXShareStatusEnum.FINISHED.toString())
                    .eq(OrderShare::getOrderShareId, share.getOrderShareId())
                    .update();
        }

        if (result.getStatus().equals(WXShareStatusEnum.FINISHED.toString())) {
            String failReason = null;
            final Map<String, ProfitSharingQueryResult.Receiver> receiverMap = result.getReceivers().stream()
                    .collect(Collectors.toMap(ProfitSharingQueryResult.Receiver::getAccount, Function.identity()));
            final ProfitSharingQueryResult.Receiver receiver = receiverMap.get(share.getOpenId());
            if (Objects.isNull(receiver)) {
                failReason = "未发现分给" + share.getWorkUserPhone() + "的记录";
            } else {
                if (receiver.getResult().equals(WXShareResultEnum.CLOSED.toString())) {
                    final Map<String, Object> fieldMap = EnumUtil.getNameFieldMap(WXShareFailReasonEnum.class, "name");
                    final Object o = fieldMap.get(receiver.getFailReason());
                    failReason = Objects.nonNull(o) ?  o.toString() : receiver.getResult();
                }
            }
            orderShareService.lambdaUpdate()
                    .set(OrderShare::getShareFailReason, failReason)
                    .set(OrderShare::getShareResult, receiver.getResult())
                    .set(StringUtils.isNotBlank(failReason), OrderShare::getStatus, OrderShareStatusEnum.EXCEPTION.toString())
                    .set(OrderShare::getShareStatus, WXShareStatusEnum.FINISHED.toString())
                    .eq(OrderShare::getOrderShareId, share.getOrderShareId())
                    .update();
        }
    }

    public String queryMaxShareRate(String id) throws Exception {
        return wechatLogic.queryMaxShareRate(id);
    }
}
