package com.sckw.order.dubbo;

import com.alibaba.fastjson2.JSON;
import com.google.common.collect.Lists;
import com.sckw.contract.api.RemoteContractService;
import com.sckw.core.exception.BusinessException;
import com.sckw.core.utils.BeanUtils;
import com.sckw.core.utils.CollectionUtils;
import com.sckw.core.utils.StringUtils;
import com.sckw.core.web.response.HttpResult;
import com.sckw.mongo.model.SckwTradeOrder;
import com.sckw.order.api.dubbo.TradeOrderInfoService;
import com.sckw.order.api.model.*;
import com.sckw.order.enums.DeliveryTypeEnum;
import com.sckw.order.enums.OrderStatusEnum;
import com.sckw.order.model.KwoTradeOrder;
import com.sckw.order.model.KwoTradeOrderContract;
import com.sckw.order.model.KwoTradeOrderTrack;
import com.sckw.order.serivce.KwoTradeOrderContractService;
import com.sckw.order.serivce.KwoTradeOrderService;
import com.sckw.order.serivce.KwoTradeOrderTrackService;
import com.sckw.order.serivce.KwoTradeOrderUnitService;
import com.sckw.redis.constant.RedisConstant;
import com.sckw.redis.utils.RedissonUtils;
import com.sckw.stream.model.SckwBusSum;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.stream.function.StreamBridge;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.Set;

/**
 * @desc: 订单dubbo实现
 * @author: yzc
 * @date: 2023-07-18 18:26
 */
@DubboService(group = "design", version = "1.0.0")
@Slf4j
public class TradeOrderInfoServiceImpl implements TradeOrderInfoService {

    @Autowired
    private KwoTradeOrderService kwoTradeOrderService;
    @Autowired
    private StreamBridge streamBridge;
    @Autowired
    private KwoTradeOrderTrackService kwoTradeOrderTrackService;
    @Autowired
    private KwoTradeOrderContractService kwoTradeOrderContractService;
    @Autowired
    private KwoTradeOrderUnitService tradeOrderUnitService;

    @DubboReference(version = "1.0.0", group = "design", check = false)
    private RemoteContractService remoteContractService;


    @Override
    public OrderDetailRes getOrderDetailById(Long tOrderId) {
        return BeanUtils.copyProperties(kwoTradeOrderService.detail(tOrderId), OrderDetailRes.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateOrderStatus(UpdateOrderStatusParam param) {
        if (Objects.isNull(param.getUpdateBy()) || StringUtils.isBlank(param.getUpdateByName())) {
            throw new BusinessException("操作人信息不能为空!");
        }
        KwoTradeOrder order = kwoTradeOrderService.getById(param.getTOrderId());
        if (Objects.isNull(order)) {
            throw new BusinessException("订单不存在!");
        }
        Integer status = param.getStatus();
        Long updateBy = param.getUpdateBy();
        if (Objects.equals(status, OrderStatusEnum.RECONCILED.getCode())) {
            if (!Objects.equals(order.getStatus(), OrderStatusEnum.FINISHED.getCode())) {
                throw new BusinessException("已完结的订单才可对账!");
            }
        } else if (Objects.equals(status, OrderStatusEnum.SETTLED.getCode())) {
            if (!Objects.equals(order.getStatus(), OrderStatusEnum.RECONCILED.getCode())) {
                throw new BusinessException("已对账的订单才可结算!");
            }
        } else {
            throw new BusinessException("非法订单状态操作！");
        }
        order.setStatus(status).setUpdateBy(updateBy);
        kwoTradeOrderService.updateById(order);
        //订单状态记录
        KwoTradeOrderTrack track = new KwoTradeOrderTrack();
        track.setTOrderId(order.getId()).setTOrderNo(order.getTOrderNo()).setStatus(order.getStatus())
                .setCreateBy(updateBy).setUpdateBy(updateBy);
        kwoTradeOrderTrackService.insert(track);
        //更新mongodb
        SckwTradeOrder updateParam = new SckwTradeOrder();
        updateParam.setTOrderId(order.getId()).setStatus(order.getStatus()).setUpdateBy(param.getUpdateBy())
                .setUpdateByName(param.getUpdateByName()).setUpdateTime(new Date());
        saveMongoDb(updateParam);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public HttpResult createOrCancelLogisticsOrder(CreateOrCancelLogisticsOrderParam param) {
        Long id = param.getTOrderId();
        BigDecimal entrustAmount = param.getEntrustAmount();
        Long updateBy = param.getUpdateBy();
        String updateByName = param.getUpdateByName();
        if (Objects.isNull(updateBy) || StringUtils.isBlank(updateByName)) {
            return HttpResult.error("操作人信息不能为空!");
        }
        if (Objects.isNull(entrustAmount)) {
            return HttpResult.error("任务量不能为空!");
        }
        String lockKey = String.format(RedisConstant.TORDER_UPDATE_AMOUNT_KEY, id);
        if (Boolean.FALSE.equals(RedissonUtils.tryLock(lockKey, 5L, 10L))) {
            return HttpResult.error("业务繁忙，请稍后再试!");
        }
        try {
            KwoTradeOrder order = kwoTradeOrderService.getById(id);
            if (Objects.isNull(order)) {
                return HttpResult.error("订单不存在!");
            }
            if (!Objects.equals(order.getStatus(), OrderStatusEnum.EXECUTING.getCode())) {
                return HttpResult.error("执行中的订单才可物流托运！");
            }
            BigDecimal totalEntrustAmount = Objects.isNull(order.getEntrustAmount()) ?
                    entrustAmount : entrustAmount.add(order.getEntrustAmount());
            order.setEntrustAmount(totalEntrustAmount).setUpdateBy(param.getUpdateBy());
            kwoTradeOrderService.updateById(order);
            //更新mongodb
            SckwTradeOrder updateParam = new SckwTradeOrder();
            updateParam.setTOrderId(order.getId()).setEntrustAmount(totalEntrustAmount.doubleValue())
                    .setUpdateBy(param.getUpdateBy()).setUpdateByName(param.getUpdateByName()).setUpdateTime(new Date());
            saveMongoDb(updateParam);
        } finally {
            RedissonUtils.unlock(lockKey);
        }
        return HttpResult.ok();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public HttpResult completeLogisticsOrder(CompleteLogisticsOrderParam param) {
        Long id = param.getTOrderId();
        BigDecimal actualLoadAmount = param.getActualLoadAmount();
        BigDecimal actualUnloadAmount = param.getActualUnloadAmount();
        Long updateBy = param.getUpdateBy();
        String updateByName = param.getUpdateByName();
        if (Objects.isNull(actualLoadAmount) || Objects.isNull(actualUnloadAmount)) {
            return HttpResult.error("装卸变量不能为空!");
        }
//        if (Objects.isNull(param.getIsAllComplete())) {
//            return HttpResult.error("物流订单是否已全部完结不能为空!");
//        }
        if (Objects.isNull(updateBy) || StringUtils.isBlank(updateByName)) {
            return HttpResult.error("操作人信息不能为空!");
        }
        String lockKey = String.format(RedisConstant.TORDER_UPDATE_AMOUNT_KEY, id);
        if (Boolean.FALSE.equals(RedissonUtils.tryLock(lockKey, 5L, 10L))) {
            return HttpResult.error("业务繁忙，请稍后再试!");
        }
        try {
            KwoTradeOrder order = kwoTradeOrderService.getById(id);
            if (Objects.isNull(order)) {
                return HttpResult.error("订单不存在!");
            }
            if (!Objects.equals(order.getStatus(), OrderStatusEnum.EXECUTING.getCode())) {
                return HttpResult.error("执行中的订单才可物流托运！");
            }
            BigDecimal actualAmount = Objects.isNull(order.getActualAmount()) ? BigDecimal.ZERO : order.getActualAmount();
            BigDecimal addActualAmount = Objects.equals(order.getDeliveryType(), DeliveryTypeEnum.ISSUE.getType())
                    ? actualLoadAmount : actualUnloadAmount;
            BigDecimal totalActualAmount = actualAmount.add(addActualAmount);
            order.setActualAmount(totalActualAmount).setUpdateBy(param.getUpdateBy());
            //不走自然完结
//            if (param.getIsAllComplete() && actualAmount.compareTo(order.getAmount()) >= 0) {
//                //完结订单
//                order.setStatus(OrderStatusEnum.FINISHED.getCode());
//                //记录状态
//                KwoTradeOrderTrack track = new KwoTradeOrderTrack();
//                track.setTOrderId(order.getId()).setTOrderNo(order.getTOrderNo()).setStatus(order.getStatus())
//                        .setCreateBy(updateBy).setUpdateBy(updateBy);
//                kwoTradeOrderTrackService.insert(track);
//                //更新合同履约量
//                KwoTradeOrderContract contract = kwoTradeOrderContractService.getByOrderId(order.getId());
//                remoteContractService.updatePerformed(contract.getContractId(), actualAmount);
//            }
            kwoTradeOrderService.updateById(order);
            //更新mongodb
            SckwTradeOrder updateParam = new SckwTradeOrder();
            updateParam.setTOrderId(order.getId()).setActualAmount(totalActualAmount.doubleValue()).setStatus(order.getStatus())
                    .setUpdateBy(param.getUpdateBy()).setUpdateByName(param.getUpdateByName()).setUpdateTime(new Date());
            saveMongoDb(updateParam);
        } finally {
            RedissonUtils.unlock(lockKey);
        }
        return HttpResult.ok();
    }

    @Override
    public HttpResult updateActualAmount(UpdateActualAmountParam param) {
        Long id = param.getTOrderId();
        BigDecimal actualLoadAmount = param.getActualLoadAmount();
        BigDecimal actualUnloadAmount = param.getActualUnloadAmount();
        Long updateBy = param.getUpdateBy();
        String updateByName = param.getUpdateByName();
        if (Objects.isNull(actualLoadAmount) || Objects.isNull(actualUnloadAmount)) {
            return HttpResult.error("装卸总量不能为空!");
        }
        if (Objects.isNull(updateBy) || StringUtils.isBlank(updateByName)) {
            return HttpResult.error("操作人信息不能为空!");
        }
        String lockKey = String.format(RedisConstant.TORDER_UPDATE_AMOUNT_KEY, id);
        if (Boolean.FALSE.equals(RedissonUtils.tryLock(lockKey, 5L, 10L))) {
            return HttpResult.error("业务繁忙，请稍后再试!");
        }
        try {
            KwoTradeOrder order = kwoTradeOrderService.getById(id);
            if (Objects.isNull(order)) {
                return HttpResult.error("订单不存在!");
            }
            if (!Objects.equals(order.getStatus(), OrderStatusEnum.EXECUTING.getCode())) {
                return HttpResult.error("执行中的订单才可物流托运！");
            }
            BigDecimal addActualAmount = Objects.equals(order.getDeliveryType(), DeliveryTypeEnum.ISSUE.getType())
                    ? actualLoadAmount : actualUnloadAmount;
            order.setActualAmount(addActualAmount).setUpdateBy(param.getUpdateBy());
            kwoTradeOrderService.updateById(order);
            //更新mongodb
            SckwTradeOrder updateParam = new SckwTradeOrder();
            updateParam.setTOrderId(order.getId())
                    .setActualAmount(addActualAmount.doubleValue())
                    .setStatus(order.getStatus())
                    .setUpdateBy(param.getUpdateBy())
                    .setUpdateByName(param.getUpdateByName())
                    .setUpdateTime(new Date());
            saveMongoDb(updateParam);
        } finally {
            RedissonUtils.unlock(lockKey);
        }
        return HttpResult.ok();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void contractSignCompleted(ContractSignCompletedParam param) {
        if (Objects.isNull(param.getUpdateBy()) || StringUtils.isBlank(param.getUpdateByName())) {
            throw new BusinessException("操作人信息不能为空!");
        }
        Long contractId = param.getContractId();
        Long updateBy = param.getUpdateBy();

        String lockKey = String.format(RedisConstant.TORDER_CONTRACT_UPDATE_KEY, param.getContractId());
        if (Boolean.FALSE.equals(RedissonUtils.tryLock(lockKey, 5L, 10L))) {
            throw new BusinessException("业务繁忙，请稍后再试!");
        }
        try {
            List<KwoTradeOrderContract> contracts = kwoTradeOrderContractService.getByContractId(contractId);
            if (CollectionUtils.isEmpty(contracts)) {
                log.info("合同：{}无相关联待签约的贸易订单", contractId);
                return;
            }
            List<Long> tOrderIds = contracts.stream().map(KwoTradeOrderContract::getTOrderId).toList();
            List<KwoTradeOrder> orders = kwoTradeOrderService.getWaitSignByIds(tOrderIds);
            if (CollectionUtils.isEmpty(orders)) {
                log.info("合同：{}无相关联待签约的贸易订单", contractId);
                return;
            }
            List<KwoTradeOrderTrack> tracks = Lists.newArrayList();
            List<SckwTradeOrder> tradeOrders = Lists.newArrayList();
            List<Long> ids = orders.stream().map(KwoTradeOrder::getId).toList();

            kwoTradeOrderService.contractCompletedUpdate(ids, updateBy);
            orders.forEach(e -> {
                KwoTradeOrderTrack track = new KwoTradeOrderTrack();
                track.setTOrderId(e.getId()).setTOrderNo(e.getTOrderNo())
                        .setStatus(OrderStatusEnum.EXECUTING.getCode())
                        .setCreateBy(updateBy).setUpdateBy(updateBy);
                tracks.add(track);
                SckwTradeOrder updateParam = new SckwTradeOrder();
                updateParam.setTOrderId(e.getId()).setStatus(OrderStatusEnum.EXECUTING.getCode())
                        .setUpdateBy(updateBy).setUpdateByName(param.getUpdateByName()).setUpdateTime(new Date());
                tradeOrders.add(updateParam);
            });
            kwoTradeOrderTrackService.insertBatch(tracks);
            tradeOrders.forEach(this::saveMongoDb);
        } finally {
            RedissonUtils.unlock(lockKey);
        }
    }

    @Override
    public void updateAssociateStatement(UpdateAssociateStatementParam param) {
        Long tOrderId = param.getTOrderId();
        Integer associateStatement = param.getAssociateStatement();
        Long updateBy = param.getUpdateBy();
        String updateByName = param.getUpdateByName();
        if (Objects.isNull(updateBy) || StringUtils.isBlank(updateByName)) {
            throw new BusinessException("操作人信息不能为空!");
        }
        if (Objects.isNull(tOrderId) || Objects.isNull(associateStatement)) {
            throw new BusinessException("更新订单是否关联对账单参数缺失！");
        }
        KwoTradeOrder order = kwoTradeOrderService.getById(tOrderId);
        if (Objects.isNull(order)) {
            throw new BusinessException("订单不存在!");
        }
        if (!Objects.equals(order.getStatus(), OrderStatusEnum.FINISHED.getCode())) {
            throw new BusinessException("已完结的订单才可对账!");
        }
        order.setAssociateStatement(associateStatement).setUpdateBy(updateBy).setUpdateTime(new Date());
        kwoTradeOrderService.updateById(order);
        //更新mongodb
        SckwTradeOrder updateParam = new SckwTradeOrder();
        updateParam.setTOrderId(order.getId()).setAssociateStatement(associateStatement).setUpdateBy(updateBy)
                .setUpdateByName(updateByName).setUpdateTime(new Date());
        saveMongoDb(updateParam);

    }

    @Override
    public Boolean associateEnt(Long firstEntId, Long secondEntId) {
        Set<Long> tOrderIds = tradeOrderUnitService.associateEntOrderId(firstEntId, secondEntId);
        if (CollectionUtils.isEmpty(tOrderIds)) {
            return Boolean.FALSE;
        }
        List<KwoTradeOrder> list = kwoTradeOrderService.associateEnt(tOrderIds);
        return CollectionUtils.isNotEmpty(list);
    }

    /**
     * @desc: mq保存mongodb
     * @author: yzc
     * @date: 2023-07-17 8:43
     * @Param order:
     * @return: void
     */
    private void saveMongoDb(Object order) {
        SckwBusSum busSum = new SckwBusSum();
        busSum.setBusSumType("tradeOrder");
        busSum.setMethod(3);
        busSum.setObject(order);
        streamBridge.send("sckw-busSum", JSON.toJSONString(busSum));
    }
}
