package com.xxfc.platform.order.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.github.wxiaoqi.security.admin.bo.UserBo;
import com.github.wxiaoqi.security.admin.entity.BaseUserMemberLevel;
import com.github.wxiaoqi.security.admin.feign.UserFeign;
import com.github.wxiaoqi.security.admin.feign.rest.UserRestInterface;
import com.github.wxiaoqi.security.auth.client.config.UserAuthConfig;
import com.github.wxiaoqi.security.common.exception.BaseException;
import com.github.wxiaoqi.security.common.util.excel.ExcelExport;
import com.github.wxiaoqi.security.common.util.process.ResultCode;
import com.github.wxiaoqi.security.common.vo.PageDataVO;
import com.xxfc.platform.activity.feign.ActivityFeign;
import com.xxfc.platform.order.biz.BaseOrderBiz;
import com.xxfc.platform.order.biz.OrderCostDetailBiz;
import com.xxfc.platform.order.biz.OrderMemberDetailBiz;
import com.xxfc.platform.order.biz.OrderTemplateBiz;
import com.xxfc.platform.order.contant.enumerate.ItemTypeEnum;
import com.xxfc.platform.order.contant.enumerate.OrderStatusEnum;
import com.xxfc.platform.order.contant.enumerate.OrderTypeEnum;
import com.xxfc.platform.order.entity.BaseOrder;
import com.xxfc.platform.order.entity.OrderItem;
import com.xxfc.platform.order.pojo.dto.MemberOrderBo;
import com.xxfc.platform.order.pojo.dto.MemberOrderFindDTO;
import com.xxfc.platform.order.pojo.dto.MemberOrderStatisticsBo;
import com.xxfc.platform.order.pojo.order.MemberBO;
import com.xxfc.platform.order.pojo.price.OrderPriceVO;
import com.xxfc.platform.order.pojo.vo.MemberOrderPageVo;
import com.xxfc.platform.tour.feign.TourFeign;
import com.xxfc.platform.universal.constant.DictionaryKey;
import com.xxfc.platform.universal.feign.ThirdFeign;
import com.xxfc.platform.vehicle.feign.VehicleFeign;
import lombok.extern.log4j.Log4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.io.FileOutputStream;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.github.wxiaoqi.security.common.constant.CommonConstants.SYS_TRUE;
import static com.xxfc.platform.universal.constant.DictionaryKey.APP_ORDER;

@Service
@Log4j
public class OrderMemberService extends AbstractOrderHandle<OrderMemberDetailBiz, MemberBO> implements UserRestInterface {

    @Autowired
    TourFeign tourFeign;

    @Autowired
    VehicleFeign vehicleFeign;

    @Autowired
    ThirdFeign thirdFeign;

    @Autowired
    private BaseOrderBiz baseOrderBiz;

    @Autowired
    private UserFeign userFeign;


    private static Integer IS_CHILD = 1;
    private static Integer LEVEL_DEFAULT = 0;
    private static Integer NUMBER_ZERO = 0;
    private static Long autoCancelTime;

    @Autowired
    OrderCostDetailBiz orderCostDetailBiz;

    @Autowired
    OrderTemplateBiz orderTemplateBiz;

    @Autowired
    protected UserAuthConfig userAuthConfig;

    @Autowired
    ActivityFeign activityFeign;

    @Autowired
    public HttpServletRequest request;

    @PostConstruct
    public void init() {
        this.orderTypeEnum = OrderTypeEnum.MEMBER;
    }

    @Override
    public void initDetail(MemberBO bo) {
        super.initDetail(bo);
        initDictionary();
        BaseUserMemberLevel buml = userFeign.level(bo.getMemberLevel());
        if (!bo.getMemberLevelId().equals(buml.getId())) {
            throw new BaseException(ResultCode.PARAM_ILLEGAL_CODE, new HashSet<String>() {{
                add("MemberLevelId 和 MemberLevel不对称");
            }});
        }
        bo.setBaseUserMemberLevel(buml);
        bo.setRentFreeNum(buml.getNumber());
        bo.setRebate(buml.getDiscount());
    }

    public void initDictionary() {
        dictionaryMap = thirdFeign.dictionaryGetAll4Map().getData();
        this.autoCancelTime = Long.valueOf(dictionaryMap.get(APP_ORDER + "_" + DictionaryKey.ACT_MEMBER).getDetail());
    }

    @Override
    public void handleDetail(MemberBO bo) {
        //设置订单状态为3
        bo.getOrder().setStatus(OrderStatusEnum.ORDER_UNPAY.getCode());
        //设置订单图片
        bo.getOrder().setPicture(bo.getBaseUserMemberLevel().getItemImg());
        //设置订单名称
        bo.getOrder().setName(bo.getBaseUserMemberLevel().getName());

        OrderItem memberItem = bo.getItemByTypeEnum(ItemTypeEnum.MEMBER);
        BigDecimal amount = memberItem.getTotalAmount();

        //如果有使用优惠券，则扣减
        if (BigDecimal.ZERO.compareTo(bo.getOrder().getCouponAmount()) < 0) {
            activityFeign.use(bo.getOrder().getUserId(), bo.getTickerNo(), bo.getOrder().getNo(), channel, amount, ActivityFeign.TYPE_USE);
        }

        super.handleDetail(bo);

        //发送定时取消订单(30分钟)
        rabbitProduct.sendDelayMessage(bo.getOrder(), autoCancelTime);
    }

    @Override
    public void handleCalculate(MemberBO bo) {
        OrderPriceVO tpv = calculatePrice(bo);
        BeanUtil.copyProperties(tpv, bo.getOrder());
        BeanUtil.copyProperties(tpv, bo);
    }

    @Override
    public OrderPriceVO calculatePrice(MemberBO detail) {
        BigDecimal orderAmount = BigDecimal.ZERO;
        BigDecimal goodsAmount = BigDecimal.ZERO;
        BigDecimal realAmount = BigDecimal.ZERO;
        BigDecimal couponAmount = BigDecimal.ZERO;

        //设置Item
        OrderItem memberOrderItem = orderItemBiz.initOrderItem(detail.getBaseUserMemberLevel().getPrice(), 1, detail.getBaseUserMemberLevel().getName(), detail.getBaseUserMemberLevel().getId(), ItemTypeEnum.MEMBER);

        detail.setItems(new ArrayList<OrderItem>());
        detail.getItems().add(memberOrderItem);

        //商品价格
        goodsAmount = goodsAmount.add(memberOrderItem.getCalculateAmount(Boolean.TRUE));

        //vehicleAmount 优惠券处理
        if (null != detail.getTickerNo() && detail.getTickerNo().size() > 0) {
            couponAmount = activityFeign.use(detail.getOrder().getUserId(), detail.getTickerNo(), detail.getOrder().getNo(), channel, goodsAmount, ActivityFeign.TYPE_NO_USE);
            if (couponAmount.compareTo(BigDecimal.ZERO) > 0) {
                detail.getOrder().setCouponTickerNos(detail.getTickerNo().stream().collect(Collectors.joining(",")));
                detail.getOrder().setHasDiscount(SYS_TRUE);
                memberOrderItem.handleCouponAmount(couponAmount);
            }
        }

        //订单总价格
        orderAmount = orderAmount.add(goodsAmount);
        //真实价格
        realAmount = realAmount.add(orderAmount).subtract(couponAmount);

        //生成订单明细
        OrderPriceVO opv = new OrderPriceVO();
        opv.setOrderAmount(orderAmount);
        opv.setGoodsAmount(goodsAmount);
        opv.setRealAmount(realAmount);
        opv.setCouponAmount(couponAmount);

        return opv;
    }


    /**
     * 导出数据
     * @param memberOrderFindDTO
     */
    public void exportMemberOrderData(MemberOrderFindDTO memberOrderFindDTO) throws Exception{
        MemberOrderPageVo memberOrderPageVo = listMemberOrderPage(memberOrderFindDTO);
        List<MemberOrderBo> memberOrderBoList = memberOrderPageVo.getMemberOrderPage().getData();
        MemberOrderStatisticsBo memberOrderStatisticsBo = memberOrderPageVo.getMemberOrderStatisticsBo();

        FileOutputStream fileOutputStream = new FileOutputStream("ts.xlsx");
        ExcelExport excelExport = new ExcelExport();
        Workbook workbook = excelExport.getWorkbook();
        Sheet sheet = workbook.createSheet();
        CellStyle cellStyleHeader01 = workbook.createCellStyle();
        cellStyleHeader01.setAlignment(HorizontalAlignment.CENTER);
        sheet.autoSizeColumn(9);
        Row row1 = sheet.createRow(0);
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("YYYYMMddHHmmss");
        createHeader(row1,0,new String[]{dateTimeFormatter.format(LocalDateTime.now())+"会员订单列表"},cellStyleHeader01);
        CellRangeAddress cellRangeAddress = new CellRangeAddress(0,0,0,9);
        sheet.addMergedRegion(cellRangeAddress);
        Row row2 = sheet.createRow(1);
        Cell row2_cell1 = row2.createCell(0);
        row2_cell1.setCellValue("统计");
        row2_cell1.setCellStyle(cellStyleHeader01);
        CellRangeAddress cellRangeAddress2 = new CellRangeAddress(1,2,0,0);
        sheet.addMergedRegion(cellRangeAddress2);
        String[] header2 = new String[]{"会员订单总数(单)","会员订单总额(元)","钻石会员订单(单)","钻石会员订单总额(元)","黄金会员订单(单)","黄金会员订单总额(元)","普通会员订单(单)","普通会员订单总额(元)"};
        createHeader(row2,1,header2,cellStyleHeader01);
        String[] countData = getData(memberOrderStatisticsBo);
        createCellCount(row2,1,countData,cellStyleHeader01);

        Row row3 = sheet.createRow(4);
        String[] header3 = new String[]{"订单号","创建时间","订单状态","名称","用户姓名","手机号","上级姓名/手机号","促成人姓名/手机号","订单价格(元)","优惠金额(元)","实付金额(元)","支付时间"};
        CellRangeAddress cellRangeAddress3 = new CellRangeAddress(3,3,0,header3.length);
        sheet.addMergedRegion(cellRangeAddress3);
        createHeader(row3,0,header3,cellStyleHeader01);



        workbook.write(fileOutputStream);
        fileOutputStream.close();
        workbook.close();

    }


    private String[] getData(MemberOrderStatisticsBo memberOrderStatisticsBo){
         String totalAmount = String.valueOf(memberOrderStatisticsBo.getTotalAmount());
         String totalDiamondAmount = String.valueOf(memberOrderStatisticsBo.getDiamondOrderNum());
         String totalGoldAmount = String.valueOf(memberOrderStatisticsBo.getTotalGoldAmount());
         String totalGeneralAmount = String.valueOf(memberOrderStatisticsBo.getTotalGeneralAmount());
          return new String[]{totalAmount,totalDiamondAmount,totalGoldAmount,totalGeneralAmount};
    }

    private void createHeader(Row row, int cellStartIndex, String[] header, CellStyle cellStyle){
        for (int i =0 ;i<header.length;i++){
            Cell cell = row.createCell(cellStartIndex);
            cell.setCellValue(header[i]);
            cell.setCellStyle(cellStyle);
            cellStartIndex+=1;
        }
    }

    private void createCellCount(Row row,int CellStartIndex,String[] data,CellStyle cellStyle){
        for(int i=CellStartIndex,y=0;i<data.length;i++,y++){
            Cell cell = row.createCell(i);
            cell.setCellValue(Objects.toString(data[y]));
            cell.setCellStyle(cellStyle);
        }
    }

    public MemberOrderPageVo listMemberOrderPage(MemberOrderFindDTO memberOrderFindDTO) {
        MemberOrderPageVo memberOrderPageVo = new MemberOrderPageVo();
        MemberOrderStatisticsBo memberOrderStatisticsBo = new MemberOrderStatisticsBo();
        List<Integer> userIds = new ArrayList<>();
        PageDataVO<MemberOrderBo> pageDataVO= new PageDataVO<>();
        pageDataVO.setPageNum(memberOrderFindDTO.getPage());
        pageDataVO.setPageSize(memberOrderFindDTO.getLimit());
        pageDataVO.setData(Collections.EMPTY_LIST);

        boolean isNoNullUserName = StringUtils.isNotEmpty(memberOrderFindDTO.getName()) && memberOrderFindDTO.getName().trim().length() > 0;
        boolean isNoNullPhone = StringUtils.isNotEmpty(memberOrderFindDTO.getPhone()) && memberOrderFindDTO.getPhone().trim().length() > 0;
        boolean isNoNullLeaderPhone = StringUtils.isNotEmpty(memberOrderFindDTO.getLeaderPhone()) && memberOrderFindDTO.getLeaderPhone().trim().length() > 0;
        if (isNoNullLeaderPhone || isNoNullPhone || isNoNullUserName) {
            userIds = userFeign.findAppUserIds(memberOrderFindDTO.getPhone(),memberOrderFindDTO.getLeaderPhone(),memberOrderFindDTO.getName());
            if (CollectionUtils.isEmpty(userIds)){
                memberOrderPageVo.setMemberOrderStatisticsBo(memberOrderStatisticsBo);
                memberOrderPageVo.setMemberOrderPage(pageDataVO);
                return memberOrderPageVo;
            }
         }
        if (memberOrderFindDTO.getPage() == 1){
            memberOrderFindDTO.setUserIds(userIds);
            memberOrderFindDTO.setIsPay(true);
            List<MemberOrderBo> baseOrders = baseOrderBiz.findMemberOrders(memberOrderFindDTO);
          /*  if (CollectionUtils.isEmpty(baseOrders)){
                 memberOrderPageVo.setMemberOrderStatisticsBo(memberOrderStatisticsBo);
                 memberOrderPageVo.setMemberOrderPage(pageDataVO);
                 return memberOrderPageVo;
            }*/
            memberOrderStatisticsBo = getMemberOrderStatisticsBo(baseOrders);
        }
        memberOrderFindDTO.setIsPay(false);
        memberOrderPageVo.setMemberOrderStatisticsBo(memberOrderStatisticsBo);

        List<MemberOrderBo> memberOrderBoList;
        if (!memberOrderFindDTO.getIsExport()){
            memberOrderFindDTO.setUserIds(userIds);
            pageDataVO = baseOrderBiz.findMemberOrderPage(memberOrderFindDTO);
            memberOrderBoList = pageDataVO.getData();
            if (CollectionUtils.isEmpty(memberOrderBoList)){
                memberOrderPageVo.setMemberOrderStatisticsBo(memberOrderStatisticsBo);
                memberOrderPageVo.setMemberOrderPage(pageDataVO);
                return memberOrderPageVo;
            }
        }else {
            memberOrderFindDTO.setUserIds(userIds);
            memberOrderBoList = baseOrderBiz.findMemberOrders(memberOrderFindDTO);
        }
        memberOrderBoList = getUserBos(memberOrderBoList);
        pageDataVO.setData(memberOrderBoList);
        memberOrderPageVo.setMemberOrderPage(pageDataVO);
        return memberOrderPageVo;
    }

    private List<MemberOrderBo> getUserBos(List<MemberOrderBo> memberOrderBoList) {
        List<UserBo> userBos = memberOrderBoList.stream().map(x -> {
            UserBo userBo = new UserBo();
            userBo.setUserId(x.getUserId());
            userBo.setOrderNo(x.getOrderNo());
            userBo.setFacilitateId(x.getFacilitateId());
            return userBo;
        }).collect(Collectors.toList());
        List<UserBo> userDTOList = userFeign.findUserDetailByUserBo(userBos);
        Map<String, UserBo> userBoMap = userDTOList.stream().collect(Collectors.toMap(UserBo::getOrderNo, Function.identity()));
        for (MemberOrderBo memberOrderBo : memberOrderBoList) {
            UserBo userBo = userBoMap.get(memberOrderBo.getOrderNo());
            if(Objects.nonNull(userBo)) {
                memberOrderBo.setUserName(userBo.getName());
                memberOrderBo.setPhone(userBo.getPhone());
                memberOrderBo.setLeaderName(userBo.getLeaderName());
                memberOrderBo.setLeaderPhone(userBo.getLeaderPhone());
                memberOrderBo.setFacilitateName(userBo.getFacilitateName());
                memberOrderBo.setCouponAmount(memberOrderBo.getCouponAmount() == null ? BigDecimal.ZERO : memberOrderBo.getCouponAmount());
                memberOrderBo.setRealAmount(memberOrderBo.getRealAmount() == null ? BigDecimal.ZERO : memberOrderBo.getRealAmount());
            }
        }
        return memberOrderBoList;
    }

    private MemberOrderStatisticsBo getMemberOrderStatisticsBo(List<MemberOrderBo> baseOrders){
        MemberOrderStatisticsBo memberOrderStatisticsBo = new MemberOrderStatisticsBo();
        Map<BigDecimal, List<MemberOrderBo>> baseOrderMap = baseOrders.stream().collect(Collectors.groupingBy(MemberOrderBo::getOrderAmount, Collectors.toList()));
        memberOrderStatisticsBo.setOrderNum(baseOrders.size());
        BigDecimal totalAmount = baseOrders.stream().map(MemberOrderBo::getOrderAmount).reduce(BigDecimal.ZERO, (x, y) -> x.add(y));
        memberOrderStatisticsBo.setTotalAmount(totalAmount);

        List<MemberOrderBo> diamondOrders = baseOrderMap.get(levelEnum.DIAMOND.getPrice());
        diamondOrders = diamondOrders ==null?Collections.EMPTY_LIST:diamondOrders;
        memberOrderStatisticsBo.setDiamondOrderNum(diamondOrders.size());
        BigDecimal diamondAmount = diamondOrders.stream().map(MemberOrderBo::getOrderAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
        memberOrderStatisticsBo.setTotalDiamondAmount(diamondAmount);

        List<MemberOrderBo> goldOrders = baseOrderMap.get(levelEnum.GOLD.getPrice());
        goldOrders = goldOrders==null?Collections.EMPTY_LIST:goldOrders;
        memberOrderStatisticsBo.setGoldOrderNum(goldOrders.size());
        BigDecimal goldAmount = goldOrders.stream().map(MemberOrderBo::getOrderAmount).reduce(BigDecimal.ZERO, (x, y) -> x.add(y));
        memberOrderStatisticsBo.setTotalGoldAmount(goldAmount);

        List<MemberOrderBo> generalOrders = baseOrderMap.get(levelEnum.GENERAL.getPrice());
        generalOrders = generalOrders==null?Collections.EMPTY_LIST:generalOrders;
        memberOrderStatisticsBo.setGeneralOrderNum(generalOrders.size());
        BigDecimal generalAmount = generalOrders.stream().map(MemberOrderBo::getOrderAmount).reduce(BigDecimal.ZERO, (x, y) -> x.add(y));
        memberOrderStatisticsBo.setTotalGeneralAmount(generalAmount);

        return memberOrderStatisticsBo;
    }
    private enum  levelEnum{
        DIAMOND(new BigDecimal("0.20"),"钻石会员"),
        GOLD(new BigDecimal("0.10"),"黄金会员"),
        GENERAL(new BigDecimal("0.05"),"普通会员");

        levelEnum(BigDecimal price, String desc) {
            this.price = price;
            this.desc = desc;
        }

        private BigDecimal price;
        private String desc;

        public BigDecimal getPrice() {
            return price;
        }

        public void setPrice(BigDecimal price) {
            this.price = price;
        }

        public String getDesc() {
            return desc;
        }

        public void setDesc(String desc) {
            this.desc = desc;
        }
    }

}
