package com.yc.ship.module.trade.convert.order;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONObject;
import com.yc.ship.framework.common.lang.Asserts;
import com.yc.ship.framework.common.util.collection.CollectionUtils;
import com.yc.ship.framework.common.util.date.DateUtils;
import com.yc.ship.framework.common.util.object.BeanUtils;
import com.yc.ship.module.otc.api.store.dto.StoreMachineDTO;
import com.yc.ship.module.product.api.dto.ProductSpuRespDTO;
import com.yc.ship.module.product.enums.ProductTypeEnum;
import com.yc.ship.module.trade.api.dto.TradeModifyVisitorReqDTO;
import com.yc.ship.module.trade.api.dto.TradeOrderCreateReqDTO;
import com.yc.ship.module.trade.api.dto.TradeOrderDispatchReqDTO;
import com.yc.ship.module.trade.api.dto.TradeOrderRespDTO;
import com.yc.ship.module.trade.controller.admin.order.vo.order.*;
import com.yc.ship.module.trade.controller.admin.smsProduct.vo.SmsProductRespVO;
import com.yc.ship.module.trade.controller.app.ota.vo.OtaVoucherVO;
import com.yc.ship.module.trade.controller.app.otc.vo.AppOtcTradeOrderCreateRespVO;
import com.yc.ship.module.trade.dal.dataobject.order.*;
import com.yc.ship.module.trade.service.order.bo.TradeDetailBO;
import com.yc.ship.module.trade.service.order.bo.TradeOrderLogCreateReqBO;
import com.yc.ship.module.trade.service.order.bo.TradeVisitorBO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import java.util.List;



@Mapper
public interface TradeOrderConvert {

    TradeOrderConvert INSTANCE = Mappers.getMapper(TradeOrderConvert.class);

    @Mappings({
            @Mapping(source = "createReqDTO.orderProperty.visitorType", target = "visitorType"),
            @Mapping(source = "createReqDTO.orderProperty.sellMethod", target = "sellMethod"),
            @Mapping(source = "createReqDTO.orderProperty.sourceId", target = "sourceId"),
            @Mapping(source = "createReqDTO.orderProperty.sourceName", target = "sourceName"),
            @Mapping(source = "createReqDTO.orderProperty.memberId", target = "memberId"),
            @Mapping(source = "createReqDTO.orderProperty.sellerId", target = "sellerId"),
            @Mapping(source = "createReqDTO.orderProperty.storeId", target = "storeId"),
            @Mapping(source = "createReqDTO.orderProperty.storeName", target = "storeName"),
            @Mapping(source = "createReqDTO.orderProperty.shareName", target = "shareName"),
    })
    TradeOrderDO convert(TradeOrderCreateReqDTO createReqDTO);
    default TradeDetailDO convert(TradeOrderDO tradeOrderDO, TradeOrderCreateReqDTO orderCreateReqDTO, TradeOrderCreateReqDTO.OrderItem orderItem, TradeOrderCreateReqDTO.OrderDetail orderDetail,
                                  ProductSpuRespDTO productSpuRespDTO, TradeOrderHotelDO tradeOrderHotelDO){
        TradeDetailDO tradeDetailDO = new TradeDetailDO();
        tradeDetailDO.setOrderId(tradeOrderDO.getId());
        tradeDetailDO.setUseDate(orderItem.getUseDate() == null ? DateUtil.toLocalDateTime(tradeOrderDO.getTravelDate())
                : DateUtil.toLocalDateTime(orderItem.getUseDate()));
        tradeDetailDO.setProductId(Long.parseLong(orderItem.getProductId()));
        tradeDetailDO.setProductName(productSpuRespDTO.getProductName());
        tradeDetailDO.setPrice(orderDetail.getOriginPrice());
        tradeDetailDO.setActualPrice(orderDetail.getPrice());
        tradeDetailDO.setSpecType(orderDetail.getSpecType());
        tradeDetailDO.setProductType(orderItem.getProductType());
        tradeDetailDO.setCateType(productSpuRespDTO.getProductType());
        tradeDetailDO.setQuantityOfOne(productSpuRespDTO.getProductSaleRule().getOneLimitNum());
        tradeDetailDO.setUseRealName(productSpuRespDTO.getProductSaleRule().getIsLimitType());
        //有效门票都是需要激活的，默认立即激活
        if(productSpuRespDTO.getProductSaleRule().getActivateType()!=null && productSpuRespDTO.getProductSaleRule().getActivateType() == 1){
            //立即激活
            tradeDetailDO.setActivateStatus(1);
            tradeDetailDO.setActivateTime(LocalDateTime.now());
        }else{
            tradeDetailDO.setActivateStatus(0);
            tradeDetailDO.setActivateDays(productSpuRespDTO.getProductSaleRule().getActivateDayNum());
        }

        if(productSpuRespDTO.getProductBasicRule().getNeedPlayDate() == 1){
            //需要选择出行日期
            Asserts.isTrue(tradeDetailDO.getUseDate()!=null,"此产品需要指定使用日期{}",productSpuRespDTO.getId());
            Date travelDate = DateUtils.of(tradeDetailDO.getUseDate());
            switch (productSpuRespDTO.getProductBasicRule().getValidityType()){
                case 1:
                    //出行当天
                    tradeDetailDO.setValidityStartDate(tradeDetailDO.getUseDate());
                    tradeDetailDO.setValidityEndDate(DateUtil.endOfDay(travelDate).toLocalDateTime());
                    break;
                case 3:
                    //出行日期前后X天内
                    tradeDetailDO.setValidityStartDate(DateUtil.offsetDay(travelDate,-productSpuRespDTO.getProductBasicRule().getValidityNum()).toLocalDateTime());
                    tradeDetailDO.setValidityEndDate(DateUtil.endOfDay(DateUtil.offsetDay(travelDate,productSpuRespDTO.getProductBasicRule().getValidityNum())).toLocalDateTime());
                    break;
                case 4:
                    //出行日期至指定日期
                    tradeDetailDO.setValidityStartDate(tradeDetailDO.getUseDate());
                    Date validityDate =DateUtils.of(productSpuRespDTO.getProductBasicRule().getValidityDate());
                    tradeDetailDO.setValidityEndDate(DateUtil.endOfDay(validityDate).toLocalDateTime());
                    break;
                default:
            }
        }else {
            if(productSpuRespDTO.getProductBasicRule().getValidityType() == 2){
                //下单后X天内
                Date now = new Date();
                tradeDetailDO.setValidityStartDate(DateUtil.beginOfDay(now).toLocalDateTime());
                tradeDetailDO.setValidityEndDate(DateUtil.endOfDay(DateUtil.offsetDay(now,productSpuRespDTO.getProductBasicRule().getValidityNum())).toLocalDateTime());
            }
        }

        //酒店产品，则有效期重置。
        if(ObjectUtil.equal(tradeDetailDO.getCateType(), ProductTypeEnum.Hotel.getValue()) && tradeOrderHotelDO!=null){
            tradeDetailDO.setValidityStartDate(DateUtil.beginOfDay(tradeOrderHotelDO.getCheckinTime()).toLocalDateTime());
            tradeDetailDO.setValidityEndDate(DateUtil.endOfDay(tradeOrderHotelDO.getCheckoutTime()).toLocalDateTime());
        }

        if(productSpuRespDTO.getProductBasicRule().getCheckStartDate()!=null){
            LocalDateTime checkStartTime = productSpuRespDTO.getProductBasicRule().getCheckStartDate().atStartOfDay();
            //开始检票时间
            if(tradeDetailDO.getValidityStartDate() == null || tradeDetailDO.getValidityStartDate().isBefore(checkStartTime)){
                tradeDetailDO.setValidityStartDate(checkStartTime);
            }
        }
        if(productSpuRespDTO.getProductBasicRule().getCheckEndDate()!=null){
            LocalDateTime checkEndTime = productSpuRespDTO.getProductBasicRule().getCheckEndDate().atStartOfDay();
            DateTime checkEndDate = DateUtil.endOfDay(DateUtils.of(checkEndTime));

            //结束检票时间
            if(tradeDetailDO.getValidityEndDate() == null || tradeDetailDO.getValidityEndDate().isAfter(checkEndDate.toLocalDateTime())){
                tradeDetailDO.setValidityEndDate(checkEndDate.toLocalDateTime());
            }
        }
        if(tradeDetailDO.getValidityEndDate()!=null){
            tradeDetailDO.setValidityEndDate(tradeDetailDO.getValidityEndDate().truncatedTo(ChronoUnit.SECONDS));
        }
        return tradeDetailDO;
    }
    TradeVisitorDO convert(TradeOrderCreateReqDTO.Visitor visitor);
    TradeDetailBaseDO convert(TradeOrderCreateReqDTO.OrderDetailBase orderDetailBase);
    TradeOrderUserDO convert(TradeOrderCreateReqDTO.OrderUser orderUser);

    TradeOrderCreateReqDTO.Visitor convert(TradeVisitorDO tradeVisitorDO);
    default List<TradeOrderCreateReqDTO.Visitor> convertList(List<TradeVisitorDO> tradeVisitorDOList) {
        return CollectionUtils.convertList(tradeVisitorDOList, item -> {
            TradeOrderCreateReqDTO.Visitor visitor = convert(item);
            visitor.setOtaDetailId(item.getDetailId().toString());
            return visitor;
        });
    }
    TradeOrderCreateReqDTO.OrderDetailBase convert(TradeDetailBaseDO tradeDetailBaseDO);

    default List<OtaVoucherVO> convertToVoucherList(List<TradeVisitorBO> tradeVisitorBOList) {
        return CollectionUtils.convertList(tradeVisitorBOList, item -> {
            OtaVoucherVO otaVoucherVO = convert(item);
            return otaVoucherVO;
        });
    }
    OtaVoucherVO convert(TradeVisitorBO tradeVisitorBO);

    TradeOrderCreateReqDTO convert(OtcTradeOrderCreateReqVO otcTradeOrderCreateReqVO);
    TradeOrderCreateReqDTO convert(OtaTradeOrderCreateReqVO otaTradeOrderCreateReqVO);
    OtcTradeOrderCreateRespVO convert(TradeOrderRespDTO tradeOrderRespDTO);
    TradeOrderCreateReqDTO.OrderUser convert(TradeOrderUserDO orderUser);

    AppOtcTradeOrderCreateRespVO convertToApp(TradeOrderRespDTO tradeOrderRespDTO);

    default PayOrderReqVO.PayParams convert(PayOrderReqVO.PayParams payParams, StoreMachineDTO storeMachineDTO) {
        JSONObject extra = payParams.getExtra();
        extra = extra == null? new JSONObject():extra;
        extra.set("deviceType",11);
        extra.set("serialNum",storeMachineDTO.getPaySerialNum());
        extra.set("latitude",storeMachineDTO.getPayLatitude());
        extra.set("longitude",storeMachineDTO.getPayLongitude());
        extra.set("terminalCode",storeMachineDTO.getPayTerminalCode());
        extra.set("appVersion",storeMachineDTO.getPayAppVersion());
        payParams.setExtra(extra);
        return payParams;
    }

    TradeOrderLogDO convert(TradeOrderLogCreateReqBO reqBO);

    default List<TradeOrderCreateReqDTO.Visitor> convertToList(List<TradeVisitorBO> tradeVisitorBOList) {
        return CollectionUtils.convertList(tradeVisitorBOList, item -> {
            TradeOrderCreateReqDTO.Visitor visitor = convertToVisitor(item);
            return visitor;
        });
    }
    TradeOrderCreateReqDTO.Visitor convertToVisitor(TradeVisitorBO tradeVisitorBO);
    TradeVisitorDO convertToVisitor(TradeModifyVisitorReqDTO.VisitorItem visitorItem);


    default List<TradeDetailRespVO> convert(List<TradeDetailBO> tradeDetailList) {
        return CollectionUtils.convertList(tradeDetailList, item -> {
            TradeDetailRespVO tradeDetailRespVO = convert(item);
            return tradeDetailRespVO;
        });
    }


    TradeDetailRespVO convert(TradeDetailBO tradeDetailBO);

    default List<DetailBaseRespVO> convertBaseList(List<TradeDetailBaseDO> baseDOList) {
        return CollectionUtils.convertList(baseDOList, item -> {
            DetailBaseRespVO baseRespVO = convertBase(item);
            return baseRespVO;
        });
    }
    DetailBaseRespVO convertBase(TradeDetailBaseDO tradeDetailBO);

    TradeOrderDispatchDO convert(TradeOrderDispatchReqDTO.Detail detail);

    TradeOrderHotelDO convert(TradeOrderCreateReqDTO.HotelBooking hotelBooking);
    TradeDetailPriceDO convert(TradeOrderCreateReqDTO.DetailPrice detailPrice);
    TradeOrderDeliveryDO convert(TradeOrderCreateReqDTO.DeliveryInfo deliveryInfo);

    default OtcTradeOrderCreateReqVO convert(ShipTradeOrderCreateReqVO shipTradeOrderCreateReqVO){
        OtcTradeOrderCreateReqVO bean = BeanUtils.toBean(shipTradeOrderCreateReqVO, OtcTradeOrderCreateReqVO.class);
        return bean;
    }
    default OtcTradeOrderCreateReqVO convert(MiniTradeOrderCreateReqVO miniTradeOrderCreateReqVO){
        OtcTradeOrderCreateReqVO bean = BeanUtils.toBean(miniTradeOrderCreateReqVO, OtcTradeOrderCreateReqVO.class);
        return bean;
    }
}
