package com.xxfc.platform.order.service;

import cn.hutool.core.bean.BeanUtil;
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.enumconstant.LevelEnum;
import com.github.wxiaoqi.security.common.exception.BaseException;
import com.github.wxiaoqi.security.common.util.process.ResultCode;
import com.github.wxiaoqi.security.common.vo.PageDataVO;
import com.xxfc.platform.activity.entity.Coupon;
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.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.apache.poi.xssf.usermodel.XSSFCellStyle;
import org.apache.poi.xssf.usermodel.XSSFFont;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.format.DateTimeFormatter;
import java.util.*;
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;

    private SimpleDateFormat simleFormatter = new SimpleDateFormat("YYYY-MM-dd HH:mm:ss");

    private  DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("YYYYMMddHHmmss");

    @PostConstruct
    public void init() {
        this.channel = Coupon.CHANNEL_MEMBER;
        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,String name,OutputStream outputStream) throws Exception{
        MemberOrderPageVo memberOrderPageVo = listMemberOrderPage(memberOrderFindDTO);
        List<MemberOrderBo> memberOrderBoList = memberOrderPageVo.getMemberOrderPage().getData();
        MemberOrderStatisticsBo memberOrderStatisticsBo = memberOrderPageVo.getMemberOrderStatisticsBo();

        XSSFWorkbook hssfWorkbook = new XSSFWorkbook();
        XSSFSheet sheet = hssfWorkbook.createSheet(name+"会员订单列表");
        CellStyle headerCellStyle = createHeaderCellStyle(hssfWorkbook);
        CellStyle generalCellStyle = createGeneralCellStyle(hssfWorkbook);

        Row row1 = sheet.createRow(0);
        createHeader(row1,0,new String[]{name+"会员订单列表"},headerCellStyle);
        CellRangeAddress cellRangeAddress = new CellRangeAddress(0,0,0,11);
        sheet.addMergedRegion(cellRangeAddress);

        Row row2 = sheet.createRow(1);
        Cell row2_cell1 = row2.createCell(0);
        row2_cell1.setCellValue("统计");
        row2_cell1.setCellStyle(headerCellStyle);
        CellRangeAddress cellRangeAddress2 = new CellRangeAddress(1,2,0,0);
        sheet.addMergedRegion(cellRangeAddress2);
        String[] header2 = new String[]{"会员订单总数(单)","会员订单总额(元)","钻石会员订单(单)","钻石会员订单总额(元)","黄金会员订单(单)","黄金会员订单总额(元)","普通会员订单(单)","普通会员订单总额(元)"};
        createHeader(row2,1,header2,headerCellStyle);
        String[] countData = getData(memberOrderStatisticsBo);
        Row row4 = sheet.createRow(2);
        createCellCount(row4,1,countData,generalCellStyle);

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

        for(int i=0;i<header3.length;i++){
            sheet.setColumnWidth(i,24*256);
        }
        List<String[]> orderDataList = getMemberOrderDataList(memberOrderBoList, 12);
        createMemberOrderCellData(sheet,5,generalCellStyle,orderDataList);
        hssfWorkbook.write(outputStream);
        hssfWorkbook.close();

    }

    private List<String[]> getMemberOrderDataList(List<MemberOrderBo> memberOrderBoList,Integer size){
        List<String[]> memerOrderData = new ArrayList<>();
            String[] data;
        for (MemberOrderBo memberOrderBo : memberOrderBoList) {
              data = new String[size];
              data[0]=memberOrderBo.getOrderNo();
              data[1]=simleFormatter.format(memberOrderBo.getCreatTime());
              data[2]=memberOrderBo.getStatus()==2?"取消":memberOrderBo.getStatus()==3?"待支付":memberOrderBo.getStatus()==6?"已完成":"";
              data[3]=memberOrderBo.getName();
              data[4]=memberOrderBo.getUserName();
              data[5]=memberOrderBo.getPhone()==null?"":memberOrderBo.getPhone();
              data[6]=String.format("%s/%s",memberOrderBo.getLeaderName()==null?"":memberOrderBo.getLeaderName(),memberOrderBo.getLeaderPhone()==null?"":memberOrderBo.getLeaderPhone());
              data[7]=String.format("%s/%s",memberOrderBo.getFacilitateName()==null?"":memberOrderBo.getFacilitateName(),memberOrderBo.getFacilitatePhone()==null?"":memberOrderBo.getFacilitatePhone());
              data[8]=memberOrderBo.getOrderAmount().toString();
              data[9]=memberOrderBo.getCouponAmount().toString();
              data[10]=memberOrderBo.getRealAmount().toString();
              data[11]=memberOrderBo.getPayTime()==null?"":simleFormatter.format(new Date(memberOrderBo.getPayTime()));
              memerOrderData.add(data);
        }
        return memerOrderData;
    }

    private CellStyle createGeneralCellStyle(XSSFWorkbook hssfWorkbook){
        CellStyle cellStyleGeneral = createHeaderCellStyle(hssfWorkbook);
        cellStyleGeneral.setWrapText(true);
        XSSFFont generalFont = createFont(hssfWorkbook);
        generalFont.setBold(false);
        cellStyleGeneral.setFont(generalFont);
        return cellStyleGeneral;
    }

    private CellStyle  createHeaderCellStyle(XSSFWorkbook hssfWorkbook){
        XSSFCellStyle cellStyleHeader = hssfWorkbook.createCellStyle();
        cellStyleHeader.setAlignment(HorizontalAlignment.CENTER);
        cellStyleHeader.setVerticalAlignment(VerticalAlignment.CENTER);
        cellStyleHeader.setLocked(false);
        XSSFFont headerFont = createFont(hssfWorkbook);
        cellStyleHeader.setFont(headerFont);
        return cellStyleHeader;
    }

    private XSSFFont createFont(XSSFWorkbook hssfWorkbook){
        XSSFFont font = hssfWorkbook.createFont();
        font.setFontName("黑体");
        font.setBold(true);
        return font;
    }

    private String[] getData(MemberOrderStatisticsBo memberOrderStatisticsBo){
        String orderNum = String.valueOf(memberOrderStatisticsBo.getOrderNum());
        String totalAmount = String.valueOf(memberOrderStatisticsBo.getTotalAmount());
        String diamondOrderNum = String.valueOf(memberOrderStatisticsBo.getDiamondOrderNum());
        String totalDiamondAmount = String.valueOf(memberOrderStatisticsBo.getDiamondOrderNum());
        String goldOrderNum = String.valueOf(memberOrderStatisticsBo.getGoldOrderNum());
        String totalGoldAmount = String.valueOf(memberOrderStatisticsBo.getTotalGoldAmount());
        String generalOrderNum = String.valueOf(memberOrderStatisticsBo.getGeneralOrderNum());
        String totalGeneralAmount = String.valueOf(memberOrderStatisticsBo.getTotalGeneralAmount());
          return new String[]{orderNum,totalAmount,diamondOrderNum,totalDiamondAmount,goldOrderNum,totalGoldAmount,generalOrderNum,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 createMemberOrderCellData(Sheet sheet,int startRowIndex,CellStyle cellStyle,List<String[]> memberOrderList){
        for (String[] data : memberOrderList) {
            Row row = sheet.createRow(startRowIndex++);
            createCellCount(row,0,data,cellStyle);
        }
    }
    private void createCellCount(Row row,int CellStartIndex,String[] data,CellStyle cellStyle){
        for(int i=CellStartIndex,y=0;y<data.length;i++,y++){
            Cell cell = row.createCell(i);
            cell.setCellStyle(cellStyle);
            cell.setCellValue(data[y]);

        }
    }

    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);
        if (Objects.nonNull(memberOrderFindDTO.getEndPayTime())){
            Long payEndTime = memberOrderFindDTO.getEndPayTime()+(1000*60*60*24);
            memberOrderFindDTO.setEndPayTime(payEndTime);
        }
        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);
            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<Integer, List<MemberOrderBo>> baseOrderMap = baseOrders.stream().collect(Collectors.groupingBy(MemberOrderBo::getMemberLevel, Collectors.toList()));
        Map<Integer, List<MemberOrderBo>> baseOrderHasPayMap = baseOrders.stream().filter(x->x.getHasPay()==1).collect(Collectors.groupingBy(MemberOrderBo::getMemberLevel, Collectors.toList()));
        memberOrderStatisticsBo.setOrderNum(baseOrders.size());
        BigDecimal totalAmount = baseOrders.stream().filter(x->x.getHasPay()==1).map(MemberOrderBo::getOrderAmount).reduce(BigDecimal.ZERO, (x, y) -> x.add(y));
        memberOrderStatisticsBo.setTotalAmount(totalAmount);

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

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

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

        return memberOrderStatisticsBo;
    }
}
