package com.ruoyi.bst.order.utils;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;

import com.ruoyi.bst.area.domain.AreaVO;
import com.ruoyi.bst.area.utils.AreaUtil;
import com.ruoyi.bst.areaSub.domain.AreaSubVO;
import com.ruoyi.bst.areaSub.utils.AreaSubUtil;
import com.ruoyi.bst.channel.domain.ChannelVO;
import com.ruoyi.bst.channel.domain.enums.ChannelApiType;
import com.ruoyi.bst.device.domain.DeviceQuery;
import com.ruoyi.bst.device.domain.DeviceVO;
import com.ruoyi.bst.device.domain.enums.DeviceStatus;
import com.ruoyi.bst.order.constants.OrderConstants;
import com.ruoyi.bst.order.domain.Order;
import com.ruoyi.bst.order.domain.OrderVO;
import com.ruoyi.bst.order.domain.dto.OrderRefundDTO;
import com.ruoyi.bst.order.domain.dto.OrderRefundDetailDTO;
import com.ruoyi.bst.order.domain.enums.OrderPayType;
import com.ruoyi.bst.order.domain.vo.OrderCalcPreRideFeeVO;
import com.ruoyi.bst.order.domain.vo.OrderCalcRideFeeVO;
import com.ruoyi.bst.order.domain.vo.OrderFeeVO;
import com.ruoyi.bst.order.domain.vo.OrderInParkingVO;
import com.ruoyi.bst.order.domain.vo.OrderPrePriceVO;
import com.ruoyi.bst.suit.domain.SuitVO;
import com.ruoyi.bst.suit.domain.enums.SuitRentalUnit;
import com.ruoyi.bst.suit.domain.enums.SuitRidingRule;
import com.ruoyi.bst.suit.utils.SuitUtil;
import com.ruoyi.common.utils.MathUtils;

public class OrderUtil {

    public static OrderPrePriceVO calcPrePrice(SuitVO suit, ChannelVO channel) {
        if (suit == null || channel == null) {
            return null;
        }

        OrderPrePriceVO vo = new OrderPrePriceVO();

        // 挂账支付
        if (ChannelApiType.CREDIT.getType().equals(channel.getApiType())) {
            vo.setDepositPrice(BigDecimal.ZERO);
        }
        // 其他支付
        else {
            vo.setDepositPrice(suit.getDepositAmount());
        }

        vo.setPayAmount(vo.getDepositPrice());
        return vo;
    }

    /**
     * 判断两个价格是否一致
     * @param a 价格A
     * @param b 价格B
     * @return 是否一致
     */
    public static boolean isEquals(OrderPrePriceVO a, OrderPrePriceVO b) {
        if (a == null || b == null) {
            return false;
        }
        return MathUtils.equals(a.getDepositPrice(), b.getDepositPrice())
            && MathUtils.equals(a.getPayAmount(), b.getPayAmount());
    }


    /**
     * 计算订单费用
     * @param order 订单
     * @param area 运营区
     * @param inParkingVO 还车点
     * @param endTime 结束时间
     * @param needDispatchFee 是否需要调度费
     * @return 结果
     */
    public static OrderFeeVO calcOrderFee(OrderVO order, AreaVO area, OrderInParkingVO inParkingVO, LocalDateTime endTime, boolean needDispatchFee) {
        OrderFeeVO vo = new OrderFeeVO();

        // 骑行费
        OrderCalcPreRideFeeVO rideFee = calcRideFee(order, endTime);
        if (rideFee != null) {
            vo.setRidingFee(rideFee.getRideFee());
        }

        // 若需要调度费，则计算调度费
        if (needDispatchFee) {
            // 运营区外调度费
            if (!inParkingVO.getInArea()) {
                BigDecimal manageFee = area.getVehicleManagementFee();
                if (manageFee == null) {
                    manageFee = BigDecimal.ZERO;
                }
                vo.setManageFee(manageFee);
            }
            // 停车点外调度费
            else if (!inParkingVO.getInParking()) {
                BigDecimal dispatchFee = area.getDispatchFee();
                if (dispatchFee == null) {
                    dispatchFee = BigDecimal.ZERO;
                }
                vo.setDispatchFee(dispatchFee);
            }
        }

        // 总费用
        vo.setTotalFee(MathUtils.addDecimal(
                vo.getRidingFee(),
                vo.getDispatchFee(),
                vo.getManageFee()
        ));

        return vo;
    }

    /**
     * 获取在停车点信息
     * @param area 运营区
     * @param areaSubList 运营区子区域列表
     * @param device 设备
     * @param lon 手机定位经度
     * @param lat 手机定位纬度
     * @return
     */
    public static OrderInParkingVO getInParkingVO(AreaVO area, List<AreaSubVO> parkingList, List<AreaSubVO> noParkingList, DeviceVO device, BigDecimal lon, BigDecimal lat) {
        if (device == null) {
            return null;
        }
        OrderInParkingVO vo = new OrderInParkingVO();
        BigDecimal areaError = area == null ? BigDecimal.ZERO : area.getError();
        BigDecimal deviceLon = device.getLongitude();
        BigDecimal deviceLat = device.getLatitude();

        // 停车区数量
        int parkingCount = parkingList == null ? 0 : parkingList.size();
        vo.setParkingCount(parkingCount);

        // 通过设备定位获取所在停车点
        AreaSubVO deviceAreaSub = AreaSubUtil.getInAreaSub(parkingList, deviceLon, deviceLat, areaError);
        vo.setDeviceAreaSub(deviceAreaSub);
        // 通过手机定位获取所在停车点
        AreaSubVO mobileAreaSub = AreaSubUtil.getInAreaSub(parkingList, lon, lat, areaError);
        vo.setMobileAreaSub(mobileAreaSub);
        // 是否在停车点
        boolean inParking = deviceAreaSub != null || mobileAreaSub != null;
        vo.setInParking(inParking);

        // 实际停车点
        if (deviceAreaSub != null) {
            vo.setActualAreaSub(deviceAreaSub);
            vo.setActualLon(device.getLongitude());
            vo.setActualLat(device.getLatitude());
        } else if (mobileAreaSub != null) {
            vo.setActualAreaSub(mobileAreaSub);
            vo.setActualLon(lon);
            vo.setActualLat(lat);
        }

        // 通过设备定位获取是否在禁停区
        AreaSubVO deviceNoParking = AreaSubUtil.getInAreaSub(noParkingList, deviceLon, deviceLat, areaError);
        vo.setDeviceNoParking(deviceNoParking);
        // 通过手机定位获取是否在禁停区
        AreaSubVO mobileNoParking = AreaSubUtil.getInAreaSub(noParkingList, lon, lat, areaError);
        vo.setMobileNoParking(mobileNoParking);
        // 是否在禁停区
        boolean inNoParking = deviceNoParking != null || mobileNoParking != null;
        vo.setInNoParking(inNoParking);

        // 通过设备定位获取是否在运营区
        boolean deviceInArea = AreaUtil.isInAreaMax(area, deviceLon, deviceLat);  // 是否在运营区
        vo.setDeviceInArea(deviceInArea);
        // 通过手机定位获取是否在运营区
        boolean mobileInArea = AreaUtil.isInAreaMax(area, lon, lat);  // 是否在运营区
        vo.setMobileInArea(mobileInArea);
        // 是否在运营区
        boolean inArea = deviceInArea || mobileInArea;
        vo.setInArea(inArea);

        return vo;
    }

    /**
     * 计算可人工退款的金额
     */
    public static BigDecimal calcCanAdminRefundAmount(OrderVO order, String refundType) {
        if (order == null) {
            return BigDecimal.ZERO;
        }
        if (OrderConstants.REFUND_TYPE_RIDE.equals(refundType)) {
            return MathUtils.subtractDecimal(order.getRidePayAmount(), order.getRidePayRefunding(), order.getRidePayRefunded());
        } else if (OrderConstants.REFUND_TYPE_DEPOSIT.equals(refundType)) {
            return MathUtils.subtractDecimal(order.getPayedAmount(), order.getPayRefunding(), order.getPayRefunded());
        }
        return BigDecimal.ZERO;
    }

    /**
     * 计算可自动退款的金额
     **/
    public static BigDecimal calcCanAutoRefundAmount(OrderVO order) {
        if (order == null) {
            return BigDecimal.ZERO;
        }
        return MathUtils.subtractDecimal(order.getPayedAmount(), order.getPayRefunding(), order.getPayRefunded(), order.getDepositDeductionAmount());
    }

    /**
     * 转为可替换的设备查询
     * @param order
     * @return
     */
    public static DeviceQuery toChangeDeviceQuery(OrderVO order) {
        DeviceQuery query = new DeviceQuery();
        query.setAreaId(order.getAreaId());
        query.setSuitId(order.getSuitId());
        query.setMchId(order.getDeviceMchId());
        query.setStatusList(DeviceStatus.canUse());
        return query;
    }

    /**
     * 剩余可抵扣押金
     * @param order
     * @return
     */
    public static BigDecimal calcRemainCanDeductDeposit(OrderVO order) {
        if (order == null) {
            return BigDecimal.ZERO;
        }
        return MathUtils.dv(order.getDepositDeductRemain());
    }

    /**
     * 计算应收总费用
     * @param data
     * @return
     */
    public static BigDecimal calcTotalFee(Order data) {
        if (data == null) {
            return BigDecimal.ZERO;
        }
        return MathUtils.addDecimal(
            data.getRidingFee(),
            data.getDispatchFee(),
            data.getManageFee(),
            data.getDeductionFee()
        );
    }

    public static OrderRefundDetailDTO calcRefundDetail(OrderVO order, OrderRefundDTO dto, String refundType) {
        OrderRefundDetailDTO result = new OrderRefundDetailDTO();
        BigDecimal deductionRefund = null;
        BigDecimal ridingRefund = null;
        BigDecimal dispatchRefund = null;
        BigDecimal manageRefund = null;
        // 押金退款
        if (OrderConstants.REFUND_TYPE_DEPOSIT.equals(refundType)) {
            deductionRefund = dto.getDeductionRefund();
            if (OrderPayType.DEPOSIT_DEDUCTION.getCode().equals(order.getPayType())) {
                ridingRefund = dto.getRidingRefund();
                dispatchRefund = dto.getDispatchRefund();
                manageRefund = dto.getManageRefund();
            }
        }
        // 支付退款
        else if (OrderConstants.REFUND_TYPE_RIDE.equals(refundType)) {
            ridingRefund = dto.getRidingRefund();
            dispatchRefund = dto.getDispatchRefund();
            manageRefund = dto.getManageRefund();
            if (OrderPayType.DEPOSIT_DEDUCTION.getCode().equals(order.getPayType())) {
                ridingRefund = BigDecimal.ZERO;
                dispatchRefund = BigDecimal.ZERO;
                manageRefund = BigDecimal.ZERO;
            }
        }

        result.setRidingRefund(MathUtils.dv(ridingRefund));
        result.setDispatchRefund(MathUtils.dv(dispatchRefund));
        result.setManageRefund(MathUtils.dv(manageRefund));
        result.setDeductionRefund(MathUtils.dv(deductionRefund));
        return result;
    }

    /**
     * 判断两个骑行费用是否一致
     * @param a 费用A
     * @param b 费用B
     * @return 是否一致
     */
    public static boolean isEquals(OrderCalcRideFeeVO a, OrderCalcRideFeeVO b) {
        if (a == null || b == null) {
            return false;
        }
        return MathUtils.equals(a.getDiscountAmount(), b.getDiscountAmount())
            && MathUtils.equals(a.getPayAmount(), b.getPayAmount());
    }

    /**
     * 计算骑行费
     * @param order
     * @param endTime
     * @return
     */
    public static OrderCalcPreRideFeeVO calcRideFee(OrderVO order, LocalDateTime endTime) {
        if (order == null || endTime == null || order.getStartTime() == null) {
            return null;
        }

        OrderCalcPreRideFeeVO vo = new OrderCalcPreRideFeeVO();


        Duration duration = Duration.between(order.getStartTime(), endTime);
        long seconds = duration.getSeconds();   // 使用时长
        vo.setSeconds(seconds);

        Integer freeRideMinutes = order.getSuitFreeRideTime();  // 免费骑行时长
        boolean isFree = freeRideMinutes != null && seconds <= freeRideMinutes * 60;  // 是否免费

        // 若免费，则骑行费为0
        if (isFree) {
            vo.setRideFee(BigDecimal.ZERO);
        }
        // 否则，计算骑行费
        else {
            SuitRentalUnit rentalUnit = SuitRentalUnit.parse(order.getSuitRentalUnit());
            if (SuitRidingRule.START_FEE.getCode().equals(order.getSuitRidingRule())) {
                vo.setRideFee(SuitUtil.calcAmountForStartFee(seconds, order.getSuitStartRule(), rentalUnit));
            } else {
                vo.setRideFee(SuitUtil.calcAmountForIntervalFee(seconds, order.getSuitIntervalRule(), rentalUnit));
            }
        }

        return vo;
    }

    /**
     * 是否挂账订单
     * @param order
     * @return
     */
    public static boolean isCredit(OrderVO order) {
        return order != null && order.getIsCredit() != null && order.getIsCredit();
    }
}
