package com.yc.ship.module.trade.service.otc.impl;

import cn.hutool.core.date.DateUtil;
import com.alibaba.excel.util.DateUtils;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.yc.ship.framework.common.lang.Asserts;
import com.yc.ship.framework.common.pojo.CommonResult;
import com.yc.ship.framework.common.pojo.PageResult;
import com.yc.ship.framework.common.util.object.BeanUtils;
import com.yc.ship.framework.security.core.LoginUser;
import com.yc.ship.module.infra.api.config.ConfigApi;
import com.yc.ship.module.ota.api.OtaDistributorApi;
import com.yc.ship.module.ota.api.dto.DistributorRespDTO;
import com.yc.ship.module.product.api.ProductApi;
import com.yc.ship.module.product.api.dto.VoyageRespDTO;
import com.yc.ship.module.product.framework.lock.ProductRedisKeyConstants;
import com.yc.ship.module.resource.api.route.RouteApi;
import com.yc.ship.module.resource.api.route.dto.RouteRespDTO;
import com.yc.ship.module.resource.api.ship.ShipApi;
import com.yc.ship.module.resource.api.ship.dto.ShipRespDTO;
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.orderjzdetail.vo.OrderJzDetailSaveReqVO;
import com.yc.ship.module.trade.controller.app.otc.vo.*;
import com.yc.ship.module.trade.convert.order.TradeOrderConvert;
import com.yc.ship.module.trade.dal.dataobject.order.TradeOrderRoomModelDO;
import com.yc.ship.module.trade.dal.dataobject.order.TradeOrderTotalDO;
import com.yc.ship.module.trade.dal.dataobject.order.TradeVisitorDO;
import com.yc.ship.module.trade.dal.mysql.order.TradeOrderRoomModelMapper;
import com.yc.ship.module.trade.dal.mysql.order.TradeOrderTotalMapper;
import com.yc.ship.module.trade.dal.mysql.order.TradeVisitorMapper;
import com.yc.ship.module.trade.enums.PayAccountTypeEnum;
import com.yc.ship.module.trade.enums.SellMethodEnum;
import com.yc.ship.module.trade.enums.TradeOrderOperateTypeEnum;
import com.yc.ship.module.trade.framework.annotation.TradeOrderLog;
import com.yc.ship.module.trade.framework.mq.TradePublishUtils;
import com.yc.ship.module.trade.service.order.TradeOrderService;
import com.yc.ship.module.trade.service.orderjzdetail.OrderJzDetailService;
import com.yc.ship.module.trade.service.otc.AppOtcTradeOrderService;
import com.yc.ship.module.trade.service.otc.OtcTradeOrderService;
import com.yc.ship.module.trade.service.pay.TradeOrderPayService;
import lombok.extern.slf4j.Slf4j;
import org.jetbrains.annotations.NotNull;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static com.yc.ship.framework.security.core.util.SecurityFrameworkUtils.getLoginUserNickname;
import static com.yc.ship.module.trade.enums.ErrorCodeConstants.ORDER_PAY_TENAND_FAIL;


/**
 * &#064;Description 旅行社订单交易service实现
 * &#064;Date 2025/8/12 08:34
 *
 * @author qsl
 */
@Service
@Slf4j
public class AppOtcTradeOrderServiceImpl implements AppOtcTradeOrderService {

    @Resource
    private ConfigApi configApi;
    @Resource
    private TradeOrderService tradeOrderService;
    @Resource
    private TradeOrderPayService tradeOrderPayService;
    @Resource
    private OtcTradeOrderService otcTradeOrderService;
    @Resource
    private ProductApi productApi;

    @Resource
    private TradeOrderTotalMapper tradeOrderTotalMapper;
    @Resource
    private TradeOrderRoomModelMapper tradeOrderRoomModelMapper;

    @Resource
    private OtaDistributorApi otaDistributorApi;

    @Resource
    private RouteApi routeApi;

    @Resource
    private ShipApi shipApi;

    @Resource
    private RedissonClient redissonClient;

    @Resource
    private TradePublishUtils tradePublishUtils;

    @Resource
    private TradeVisitorMapper tradeVisitorMapper;

    @Resource
    private OrderJzDetailService orderJzDetailService;


    @Override
    @Transactional(rollbackFor = Exception.class)
    @TradeOrderLog(operateType = TradeOrderOperateTypeEnum.ORDER_CREATE)
    public CommonResult<OtcTradeOrderCreateRespVO> miniAppCreateOrder(LoginUser loginUser, MiniTradeOrderCreateReqVO miniTradeOrderCreateReqVO) {
        TradeOrderOtcCreateVO createVO = BeanUtils.toBean(miniTradeOrderCreateReqVO, TradeOrderOtcCreateVO.class);
        Long distributorId = createVO.getDistributorId();
        if (distributorId != null) {
            DistributorRespDTO distributor = otaDistributorApi.getDistributorById(distributorId);
            if (distributor != null) {
                createVO.setCustomerName(distributor.getName());
            }
        }
        VoyageRespDTO voyage = productApi.getVoyage(createVO.getVoyageId());
        if (voyage != null) {
            createVO.setBoardingTime(com.yc.ship.framework.common.util.date.DateUtils.of(voyage.getBoardingTime()));
            createVO.setLeaveTime(com.yc.ship.framework.common.util.date.DateUtils.of(voyage.getLeaveTime()));
        }
        createVO.setMoveOrder(false);
        createVO.setCurrency("CNY");
        createVO.setIsYd(0);
        RouteRespDTO routeRespDTO = routeApi.queryRouteById(voyage.getRouteId());
        ShipRespDTO ship = shipApi.queryShip(createVO.getShipId());
        String sname = ship.getName() + "-" + routeRespDTO.getName() + "-" + voyage.getName();
        String date = DateUtils.format(voyage.getBoardingTime(), "yyyyMMdd");
        String code = "YC";
        if (routeRespDTO != null && routeRespDTO.getDirection() == 2) {
            code = "CY";
        }
        String ccode = date + "-" + voyage.getCode() + "-";
        if(ship.getCode() != null){
            ccode = ship.getCode() + "-" + date + "-" + code + "-";
        }
        int maxOrderNo = tradeOrderService.getMaxOrderNo(createVO.getVoyageId(),ccode);
        String orderNo = ccode+(maxOrderNo + 1);

        //现在给整个订单号的加锁
        String lockKey = String.format(ProductRedisKeyConstants.ORDER_REDIS_KEY_PREFIX, orderNo);
        RLock lock = redissonClient.getLock(lockKey);

        try {
            lock.lock(60, TimeUnit.SECONDS);
            TradeOrderTotalVO summary = createVO.getSummary();
            BigDecimal realAmount = summary.getRealMoney();
            BigDecimal orderMoney = summary.getOrderMoney();
            Long discountId = summary.getDiscountId();
            BigDecimal realOrderMoney = summary.getRealOrderMoney();
            BigDecimal otherMoney = summary.getOtherMoney();
            ShipTradeOrderCreateReqVO shipTradeOrderCreateReqVO = BeanUtils.toBean(createVO, ShipTradeOrderCreateReqVO.class);
            shipTradeOrderCreateReqVO.setMoveOrder(false);
            shipTradeOrderCreateReqVO.setConfirmType(0);
            shipTradeOrderCreateReqVO.setAmount(orderMoney);
            shipTradeOrderCreateReqVO.setPayAmount(realAmount);
            if (realOrderMoney != null) {
                shipTradeOrderCreateReqVO.setPayAmount(realOrderMoney);
            }
            shipTradeOrderCreateReqVO.setRealMoney(realAmount);
            shipTradeOrderCreateReqVO.setIsRead(0);
            shipTradeOrderCreateReqVO.setOrderSort(maxOrderNo + 1);
            shipTradeOrderCreateReqVO.setOtherMoney(otherMoney);
            ShipTradeOrderCreateReqVO.OrderUser orderUser = new ShipTradeOrderCreateReqVO.OrderUser();
            orderUser.setContactName(createVO.getLinkMan());
            orderUser.setMobile(createVO.getLinkMobile());
            orderUser.setEmail(createVO.getLinkEmail());
            shipTradeOrderCreateReqVO.setOrderUser(orderUser);
            shipTradeOrderCreateReqVO.setRemark(createVO.getRemark());
            shipTradeOrderCreateReqVO.setIsYd(createVO.getIsYd());
            shipTradeOrderCreateReqVO.setTravelDate(createVO.getBoardingTime());
            shipTradeOrderCreateReqVO.setOrderNo(orderNo);
            shipTradeOrderCreateReqVO.setProductName(sname);
            ShipTradeOrderCreateReqVO.OrderProperty orderProperty = new ShipTradeOrderCreateReqVO.OrderProperty();
            orderProperty.setSellMethod(SellMethodEnum.MINI_APP.getType());
            orderProperty.setSourceId(createVO.getDistributorId() + "");
            orderProperty.setSourceName(createVO.getCustomerName());
            shipTradeOrderCreateReqVO.setOrderProperty(orderProperty);
            ShipTradeOrderCreateReqVO.OrderItem orderItem = new ShipTradeOrderCreateReqVO.OrderItem();
            List<ShipTradeOrderCreateReqVO.OrderDetail> detailList = new ArrayList<>();
            ShipTradeOrderCreateReqVO.OrderDetail orderDetail = new ShipTradeOrderCreateReqVO.OrderDetail();
            for (TradeVistorReqVO tradeVistorReqVO : createVO.getTourist()) {
                List<ShipTradeOrderCreateReqVO.Visitor> visitorList = new ArrayList<>();
                ShipTradeOrderCreateReqVO.OrderDetail visitorDetailId = new ShipTradeOrderCreateReqVO.OrderDetail();
                BeanUtils.copyProperties(orderDetail, ShipTradeOrderCreateReqVO.OrderDetail.class);
                visitorDetailId.setPrice(tradeVistorReqVO.getActualPrice());
                visitorDetailId.setOriginPrice(tradeVistorReqVO.getPrice());
                visitorDetailId.setProductType(0);
                visitorDetailId.setBoardingTime(createVO.getBoardingTime());
                visitorDetailId.setLeaveTime(createVO.getLeaveTime());
                visitorDetailId.setProductType(0);
                ShipTradeOrderCreateReqVO.Visitor visitor = getVisitor1(tradeVistorReqVO);
                visitorList.add(visitor);
                visitorDetailId.setVisitorList(visitorList);
                visitorDetailId.setCount(1);
                detailList.add(visitorDetailId);
            }
            orderItem.setDetailList(detailList);
            BigDecimal spuMoney = new BigDecimal(0);
            for (TradeSpuReqVO tradeSpuReqVO : createVO.getSpuList()) {
                ShipTradeOrderCreateReqVO.OrderDetail orderDetail1 = new ShipTradeOrderCreateReqVO.OrderDetail();
                //0 游船产品 1 附加产品 2：赠票
                if (tradeSpuReqVO.getProductId() != null && !tradeSpuReqVO.getTourist().isEmpty()) {
                    orderDetail1.setProductType(1);
                } else if (tradeSpuReqVO.getProductId() != null && tradeSpuReqVO.getRequired() != null && tradeSpuReqVO.getRequired() == 1) {
                    orderDetail1.setProductType(2);
                } else {
                    continue;
                }
                List<ShipTradeOrderCreateReqVO.Visitor> visitorList1 = new ArrayList<>();
                for (String touristId : tradeSpuReqVO.getTourist()) {
                    TradeVistorReqVO tradeVistorReqVO = createVO.getTourist().stream().filter(v -> v.getId().equals(touristId)).findFirst().orElseGet(TradeVistorReqVO::new);
                    ShipTradeOrderCreateReqVO.Visitor visitor = getVisitor1(tradeVistorReqVO);
                    visitorList1.add(visitor);
                    BigDecimal price = tradeSpuReqVO.getPrice() == null ? BigDecimal.ZERO : tradeSpuReqVO.getPrice();
                    spuMoney = spuMoney.add(price);
                }
                orderDetail1.setVisitorList(visitorList1);
                orderDetail1.setProductId(tradeSpuReqVO.getProductId() + "");
                orderDetail1.setPrice(tradeSpuReqVO.getPrice());
                orderDetail1.setOriginPrice(tradeSpuReqVO.getPrice());

                orderDetail1.setCount(visitorList1.size());
                detailList.add(orderDetail1);
            }
            shipTradeOrderCreateReqVO.setItemlList(Collections.singletonList(orderItem));

            shipTradeOrderCreateReqVO.setSpuAmount(spuMoney);

            Date travelDate = shipTradeOrderCreateReqVO.getTravelDate();
            if (DateUtil.compare(travelDate, new Date()) < 0) {
                Asserts.isTrue(false, "选择的游玩日期不能早于当前时间");
            }
            CommonResult<TradeOrderRespDTO> result;
            try {
                result = doShipCreateOrder(loginUser, shipTradeOrderCreateReqVO);
            } catch (Exception e) {
                return CommonResult.error(500, e.getMessage());
            }
            if (result.isError()) {
                return CommonResult.error(result.getCode(), result.getMsg());
            }
            TradeOrderTotalDO tradeOrderTotalDO = BeanUtils.toBean(summary, TradeOrderTotalDO.class);
            Long orderId = result.getCheckedData().getOrderId();
            tradeOrderTotalDO.setId(IdWorker.getId());
            tradeOrderTotalDO.setOldOrderId(orderId);
            tradeOrderTotalDO.setOtherRemark(summary.getOtherRemark());
            tradeOrderTotalMapper.insert(tradeOrderTotalDO);
            // 创建订单房型数据
            List<TradeOrderRoomModelDO> tradeOrderRoomDOList = new ArrayList<>();
            List<TradeOrderRoomModelVO> roomModelList = createVO.getRoomModelList();
            roomModelList.forEach(roomModel -> {
                TradeOrderRoomModelDO tradeOrderRoomDO = BeanUtils.toBean(roomModel, TradeOrderRoomModelDO.class);
                tradeOrderRoomDO.setOrderId(orderId);
                tradeOrderRoomDO.setOrderNo(orderNo);
                tradeOrderRoomDO.setDiscount(tradeOrderRoomDO.getUnitPrice().subtract(tradeOrderRoomDO.getRealMoney()));
                tradeOrderRoomDOList.add(tradeOrderRoomDO);
            });
            if (!tradeOrderRoomDOList.isEmpty()) {
                tradeOrderRoomModelMapper.deleteByOrderId(orderId);
                tradeOrderRoomModelMapper.insertBatch(tradeOrderRoomDOList);
            }
            // TODO:需要发布订单超时mq
            OtcTradeOrderCreateRespVO respVO = TradeOrderConvert.INSTANCE.convert(result.getData());
            return CommonResult.success(respVO);
        } finally {
            if (lock.isHeldByCurrentThread() && lock.isLocked()) {
                lock.unlock();
            }
        }
    }

    private CommonResult<TradeOrderRespDTO> doShipCreateOrder(LoginUser loginUser, ShipTradeOrderCreateReqVO otcTradeOrderCreateReqVO) {
        ShipTradeOrderCreateReqVO.OrderProperty orderProperty = otcTradeOrderCreateReqVO.getOrderProperty();
        if (orderProperty == null) {
            orderProperty = new ShipTradeOrderCreateReqVO.OrderProperty();
        }
        setShipOrderPropertyFromLoginUser(loginUser, orderProperty);
        otcTradeOrderCreateReqVO.setOrderProperty(orderProperty);
        return tradeOrderService.createShipOrder(otcTradeOrderCreateReqVO);
    }

    private void setShipOrderPropertyFromLoginUser(LoginUser loginUser, ShipTradeOrderCreateReqVO.OrderProperty orderProperty) {
        orderProperty.setSellerId(loginUser.getId().toString());
        orderProperty.setSellMethod(SellMethodEnum.MINI_APP.getType());
        orderProperty.setMemberId(loginUser.getId().toString());
    }

    private static ShipTradeOrderCreateReqVO.@NotNull Visitor getVisitor1(TradeVistorReqVO tradeVistorReqVO) {
        ShipTradeOrderCreateReqVO.Visitor visitor = new ShipTradeOrderCreateReqVO.Visitor();
        visitor.setName(tradeVistorReqVO.getName());
        visitor.setMobile(tradeVistorReqVO.getMobile());
        visitor.setCredentialNo(tradeVistorReqVO.getCardNo());
        visitor.setCredentialType(tradeVistorReqVO.getCardType());
        visitor.setYczz(tradeVistorReqVO.getYichang());
        visitor.setCqzz(tradeVistorReqVO.getChongqing());
        visitor.setRoomId(tradeVistorReqVO.getRoomId());
        visitor.setNationality(tradeVistorReqVO.getNationality());
        visitor.setGender(tradeVistorReqVO.getGender());
        visitor.setBirthday(tradeVistorReqVO.getBirthday());
        visitor.setType(tradeVistorReqVO.getType());
        visitor.setAge(tradeVistorReqVO.getAge());
        visitor.setRoomIndexId(tradeVistorReqVO.getRoomIndexId());
        visitor.setRoomModelId(tradeVistorReqVO.getRoomModelId());
        visitor.setFloor(tradeVistorReqVO.getFloor());
        visitor.setVid(tradeVistorReqVO.getId());
        visitor.setCohabitation(tradeVistorReqVO.getCohabitation());

        return visitor;
    }

    @Override
    public CommonResult<PayOrderRespVO> miniAppPayOrder(LoginUser loginUser, PayOrderReqVO payOrderReqVO) {
        if (loginUser == null) {
            return CommonResult.error(ORDER_PAY_TENAND_FAIL);
        }
        payOrderReqVO.setAccountType(PayAccountTypeEnum.MEMBER.getType());
        payOrderReqVO.setAccountName(getLoginUserNickname());
        return tradeOrderPayService.payOrder(payOrderReqVO);
    }

    @Override
    public CommonResult<PageResult<AppTradeOrderRespVO>> miniTradeOrderPage(AppTradeOrderPageReqVO pageReqVO) {
        PageResult<TradeOrderRespVO> pageResult = otcTradeOrderService.getMiniTradeOrderPage(pageReqVO);
        PageResult<AppTradeOrderRespVO> appPageResult = BeanUtils.toBean(pageResult, AppTradeOrderRespVO.class);
        return CommonResult.success(appPageResult);
    }

    @Override
    public CommonResult<AppTradeOrderRespVO> miniOrderInfoById(Long id) {
        TradeOrderRespVO tradeOrderRespVO = otcTradeOrderService.getOrderInfo(id);
        AppTradeOrderRespVO appTradeOrderRespVO = BeanUtils.toBean(tradeOrderRespVO, AppTradeOrderRespVO.class);
        return CommonResult.success(appTradeOrderRespVO);
    }


    @Override
    public String getConfigValue(String key) {
        return configApi.getConfigValueByKey(key);
    }

    @Override
    public CommonResult<?> miniAppCancelOrder(LoginUser loginUser, Long orderId) {
        return tradeOrderPayService.cancelOrder(orderId);
    }

    @Override
    public List<AppMyItineraryVO> getMyItinerary(Long loginUserId, Integer status, String keyword) {
        List<AppMyItineraryVO> list = tradeOrderService.getMyItinerary(loginUserId, status, keyword);
        return list;
    }

    @Override
    public AppItineraryDetailVO getItineraryDetail(Long orderId, String keyword) {
        AppItineraryDetailVO detailVO = tradeOrderService.getItineraryDetail(orderId, keyword);
        return detailVO;
    }

    @Override
    public Long appCreateOrderJzDetail(AppOrderJzReqVO reqVO) {
        String oid = reqVO.getOid();
        List<TradeVisitorDO> visitorDOList = tradeVisitorMapper.selectListByOrderId(Long.valueOf(oid));
        if (visitorDOList != null && !visitorDOList.isEmpty()) {
            List<OrderJzDetailSaveReqVO> list = new ArrayList<>();
            visitorDOList.stream().forEach(visitorDO -> {
                OrderJzDetailSaveReqVO vo = new OrderJzDetailSaveReqVO();
                vo.setName(visitorDO.getName());
                vo.setIdCard(visitorDO.getCredentialNo());
                vo.setPhone(visitorDO.getMobile() == null ? reqVO.getPhone() : visitorDO.getMobile());
                vo.setArriveTime(reqVO.getArriveTime());
                vo.setAddress(reqVO.getAddress());
                vo.setOid(oid);
                vo.setRemark(reqVO.getRemark());
                list.add(vo);
            });
            orderJzDetailService.createOrderJzDetail(list);
        }
        return 0L;
    }

}
