package com.izouma.dingdong.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.izouma.dingdong.domain.*;
import com.izouma.dingdong.domain.merchant.Merchant;
import com.izouma.dingdong.domain.rider.Rider;
import com.izouma.dingdong.domain.user.ShoppingCart;
import com.izouma.dingdong.domain.merchant.Goods;
import com.izouma.dingdong.domain.merchant.MerchantSettings;
import com.izouma.dingdong.domain.user.Address;
import com.izouma.dingdong.domain.user.UserCoupon;
import com.izouma.dingdong.dto.UserOrderDTO;
import com.izouma.dingdong.enums.*;
import com.izouma.dingdong.exception.BusinessException;
import com.izouma.dingdong.repo.*;
import com.izouma.dingdong.repo.rider.RiderRepo;
import com.izouma.dingdong.repo.user.ShoppingCartRepo;
import com.izouma.dingdong.repo.merchant.GoodsRepo;
import com.izouma.dingdong.repo.merchant.MerchantRepo;
import com.izouma.dingdong.repo.merchant.MerchantSettingsRepo;
import com.izouma.dingdong.repo.user.AddressRepo;
import com.izouma.dingdong.repo.user.UserCouponRepo;
import com.izouma.dingdong.service.merchant.GoodsService;
import com.izouma.dingdong.service.merchant.MerchantService;
import com.izouma.dingdong.service.merchant.SalesService;
import com.izouma.dingdong.service.rider.DeliveryFeeService;
import com.izouma.dingdong.utils.MapUtils;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;

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

@Service
@AllArgsConstructor
public class OrderInfoService {

    private OrderInfoRepo           orderInfoRepo;
    private CouponRepo              couponRepo;
    private OrderGoodsSpecRepo      orderGoodsSpecRepo;
    private GoodsRepo               goodsRepo;
    private GoodsService            goodsService;
    private MerchantSettingsRepo    merchantSettingsRepo;
    private ShoppingCartRepo        shoppingCartRepo;
    private AddressRepo             addressRepo;
    private UserRepo                userRepo;
    private MerchantService         merchantService;
    private SalesService            salesService;
    private MerchantRepo            merchantRepo;
    private UserCouponRepo          userCouponRepo;
    private OrderRefundApplyService orderRefundApplyService;
    private RiderRepo               riderRepo;
    private DeliveryFeeService      deliveryFeeService;
    private SysConfigRepo           sysConfigRepo;

    /*
    用户下单
     */
    public OrderInfo userOrder(UserOrderDTO userOrderDTO) {

        ShoppingCart cart = shoppingCartRepo.findById(userOrderDTO.getShoppingCartId())
                .orElseThrow(new BusinessException("不存在"));

        //商家
        MerchantSettings merchantSettings = merchantSettingsRepo.findByMerchantId(cart.getMerchantId())
                .orElseThrow(new BusinessException("无商家"));
        Merchant merchant = merchantRepo.findById(cart.getMerchantId()).orElseThrow(new BusinessException("无商家"));

        LocalTime startTime = merchantSettings.getStartTime();
        LocalTime endTime = merchantSettings.getEndTime();

        LocalDateTime now = LocalDateTime.now();
        LocalTime nowTime = LocalTime.now();

        //是否营业时间内
        if (!merchantSettings.getIsOpening()) {
            throw new BusinessException("商家未营业");
        } else if (!nowTime.isAfter(startTime) || nowTime.isAfter(endTime)) {
            throw new BusinessException("非营业时间");
        }

        //如果未设置起送金额为0
        if (ObjectUtil.isEmpty(merchantSettings.getStartingAmount())) {
            merchantSettings.setStartingAmount(BigDecimal.ZERO);
        }
        if (merchantSettings.getStartingAmount().compareTo(cart.getGoodsTotal()) > 0) {
            throw new BusinessException("未达到起送金额");
        }

        OrderInfo orderInfo = new OrderInfo();
        BeanUtil.copyProperties(userOrderDTO, orderInfo);
        BeanUtil.copyProperties(cart, orderInfo);
        orderInfo.setMerchantStatus(MerchantStatus.NOT_RECEIVED);
        orderInfo.setCancel(false);
        orderInfo.setOrderTime(now);
        orderInfo.setEnabled(true);

        //如果未设置预计到达为15分钟
        if (ObjectUtil.isEmpty(merchantSettings.getPreparationTime())) {
            merchantSettings.setPreparationTime(15L);
        }
        //预计送达时间
        //商家准备时间 + 骑手到商家的距离（因为用户下单时，骑手不知，所以为固定时间） + 用户到商家的时间
        orderInfo.setTimeOfArrival(LocalDateTime.now().plusMinutes(merchantSettings.getPreparationTime()));

        //用户地址
        Address address = addressRepo.findById(userOrderDTO.getAddressId()).orElseThrow(new BusinessException("地址不存在"));
        //判断与商家的距离
        Double distance = MapUtils.distance(address.getLongitude(), address.getLatitude(), merchant.getLongitude(), merchant
                .getLatitude());
        //获取范围
        String range = sysConfigRepo.findByName("range").orElseThrow(new BusinessException("无配置")).getValue();

        if (distance > new Double(range)) {
            throw new BusinessException("超出配送距离");
        }

        //orderInfo.setUserAddress(address.getAddressName());
        orderInfo.setUserAddress(address.getAddressInfo());
        //经度在前 纬度在后
        orderInfo.setLocation(address.getLongitude() + "," + address.getLatitude());

        //重算配送费
        BigDecimal deliveryFee = deliveryFeeService.deliveryFee(merchant.getId(), cart.getOrderGoodsSpecs(), address.getLongitude(), address
                .getLatitude());
        orderInfo.setDeliveryAmount(deliveryFee);

        // 使用优惠券(满减优惠券)
        if (ObjectUtil.isNotNull(userOrderDTO.getUserCouponId())) {
            //Coupon coupon = couponRepo.findById(userOrderDTO.getCouponId()).orElseThrow(new BusinessException("优惠券不存在"));
            UserCoupon userCoupon = userCouponRepo.findById(userOrderDTO.getUserCouponId())
                    .orElseThrow(new BusinessException("无此优惠券"));
            Coupon coupon = couponRepo.findById(userCoupon.getCouponId()).orElseThrow(new BusinessException("优惠券不存在"));
            //未过期，未使用
            if (coupon.getEndDate().isAfter(now.toLocalDate()) && !userCoupon.getIsUsed()) {
                //限制商家
                if (ObjectUtil.isNotNull(coupon.getMerchantId()) && !orderInfo.getMerchantId()
                        .equals(coupon.getMerchantId())) {
                    throw new BusinessException("指定商家优惠券");
                }

                //判断是否限制手机号
                if (ObjectUtil.isNotNull(userCoupon.getPhone()) && !address.getPhone().equals(userCoupon.getPhone())) {
                    throw new BusinessException("限手机" + userCoupon.getPhone() + "使用");
                }

                if (coupon.getFullAmount().compareTo(cart.getGoodsTotal()) <= 0) {
                    //订单金额，优惠券Id
                    orderInfo.setRedBag(coupon.getAmount());
                    orderInfo.setUserCouponId(userCoupon.getId());
                    orderInfo.setRealAmount(orderInfo.getRealAmount().subtract(orderInfo.getRedBag()));

                    userCoupon.setIsUsed(true);
                    userCoupon.setUsedTime(now);
                    userCouponRepo.save(userCoupon);
                }
            }
        }


        //设置状态已支付
        orderInfo.setStatus(OrderStatus.PAID);

        OrderInfo save = orderInfoRepo.save(orderInfo);

        cart.getOrderGoodsSpecs().forEach(s -> {
                    //查库存是否足够
                    Goods goods = goodsService.buy(s.getGoodsId(), s.getNum());
                    //商品销售时间内
                    if (goods.getStartTime().isAfter(nowTime) || goods.getEndTime().isBefore(nowTime)) {
                        throw new BusinessException("非营业时间");
                    }
                    //查商品数据，加商品销量，减商品库存
                    goods.setInventory(goods.getInventory() - s.getNum());
                    goods.setTotalSales(goods.getTotalSales() + s.getNum());
                    goodsRepo.save(goods);

                    s.setOrderInfoId(save.getId());
                    orderGoodsSpecRepo.save(s);
                }
        );

        //商家是否自动接单
        if (merchantSettings.getAutomaticOrder()) {
            merReceiveOrder(save.getId(), true);
        }

        //购物车删除
        shoppingCartRepo.deleteById(cart.getId());

        return save;

    }


    /*
    商家接单
     */
    public OrderInfo merReceiveOrder(Long orderId, Boolean pass) {
        OrderInfo orderInfo = orderInfoRepo.findById(orderId).orElseThrow(new BusinessException("无订单"));
        if (pass) {
            orderInfo.setMerchantStatus(MerchantStatus.RECEIVED);
            //通知骑手 手动
            orderInfo.setRiderId(151L);
            orderInfo.setRiderStatus(RiderStatus.RECEIVED);


        } else {
            orderInfo.setMerchantStatus(MerchantStatus.REJECTED);
            orderInfo.setCancel(true);
            orderInfo.setStatus(OrderStatus.CANCELLED);
            orderInfo.setReason(RefundReason.MERCHANT_REJECTION);
            //退款流程
            OrderRefundApply apply = orderRefundApplyService.apply(orderId, RefundReason.MERCHANT_REJECTION, "商家拒单退款", null);
            orderRefundApplyService.audit(apply.getId(), true, false);
        }
        return orderInfoRepo.save(orderInfo);
    }


    /*
    骑手改变状态
    */
    public void riderCarryOut(Long orderId, RiderStatus status, Double longitude, Double latitude) {
        OrderInfo orderInfo = orderInfoRepo.findById(orderId).orElseThrow(new BusinessException("无订单"));

        if (OrderStatus.CANCELLED.equals(orderInfo.getStatus())) {
            throw new BusinessException("订单已取消");
        }

        //RiderStatus riderStatus = orderInfo.getRiderStatus();
        switch (status) {
            //已接单状态 待取餐
            case ARRIVE:
                //判断是否到达商家位置
                Merchant merchant = orderInfo.getMerchant();
                Double latitude1 = merchant.getLatitude();
                Double longitude1 = merchant.getLongitude();
                if (MapUtils.distance(longitude, latitude, longitude1, latitude1) > 5.0) {
                    throw new BusinessException("未到店");
                }
                //待取餐
                orderInfo.setRiderStatus(RiderStatus.ARRIVE);
                break;
            case TAKE_MEAL:
                //已取餐 待送达
                orderInfo.setRiderStatus(RiderStatus.TAKE_MEAL);
                //商家状态已完成
                orderInfo.setMerchantStatus(MerchantStatus.CARRY_OUT);
                break;
            case CARRY_OUT:
                //确认是否到达用户地址位置
                Address address = addressRepo.findById(orderInfo.getAddressId())
                        .orElseThrow(new BusinessException("地址不存在"));
                Double latitude2 = address.getLatitude();
                Double longitude2 = address.getLongitude();
                if (MapUtils.distance(longitude, latitude, longitude2, latitude2) > 5) {
                    throw new BusinessException("未到用户地点");
                }
                //已送达
                orderInfo.setRiderStatus(RiderStatus.CARRY_OUT);
                orderInfo.setUserReceivedTime(LocalDateTime.now());
                orderInfo.setStatus(OrderStatus.RATED);

                //支付价钱
                orderRefundApplyService.orderCarryOut(orderId);
                //添加销量数据
                salesService.addSale(orderInfo);
                break;
        }
        orderInfoRepo.save(orderInfo);
    }

    /**
     * 按用户ID查出用户/商家/骑手订单
     *
     * @param userId 登录的ID
     * @return 订单列表
     */
    public List<OrderInfo> my(Long userId) {
        User user = userRepo.findById(userId).orElseThrow(new BusinessException("无用户"));
        if (user.getIdentity() == null) {
            throw new BusinessException("身份错误");
        }
        switch (user.getIdentity()) {
            case USER:
                return orderInfoRepo.findAllByUserId(userId);
            case MERCHANT:
                Long merchantId = merchantService.findMerchantId(userId);
                return orderInfoRepo.findAllByMerchantId(merchantId);
            case RIDER:
                Rider rider = riderRepo.findByUserId(userId).orElseThrow(new BusinessException("无用户"));
                return orderInfoRepo.findAllByRiderId(rider.getId());
        }
        return null;
    }


    /*
    用户取消订单
     */
    public OrderInfo cancel(Long id, RefundReason reason, String remark, String img) {
        OrderInfo orderInfo = orderInfoRepo.findById(id).orElseThrow(new BusinessException("无订单"));

        if (orderInfo.getStatus().equals(OrderStatus.UNPAID)) {
            //未支付，无退款，直接取消
            orderInfo.setCancel(true);
            orderInfo.setReason(reason);
            orderInfo.setStatus(OrderStatus.CANCELLED);
            return orderInfoRepo.save(orderInfo);

        }

        //订单待评价/已完成
        if (orderInfo.getStatus().equals(OrderStatus.RATED) || orderInfo.getStatus().equals(OrderStatus.COMPLETED)) {
            throw new BusinessException("订单已完成");
        }

        //用户已支付
        if (OrderStatus.PAID.equals(orderInfo.getStatus())) {

            //已接单，已完成，不能退 只能投诉
            if (RiderStatus.CARRY_OUT.equals(orderInfo.getRiderStatus())) {
                throw new BusinessException("已完成无法取消");
            }

            OrderRefundApply apply = orderRefundApplyService.apply(id, reason, remark, img);
            //商家未接单，直接退
            if (MerchantStatus.NOT_RECEIVED.equals(orderInfo.getMerchantStatus())) {
                orderRefundApplyService.audit(apply.getId(), true, false);

            } else {//商家已接单
                //骑手未接单 直接退
                if (RiderStatus.NOT_RECEIVED.equals(orderInfo.getRiderStatus())) {
                    orderRefundApplyService.audit(apply.getId(), true, false);
                }
            }
        }
        // orderInfo.setCancel(true);
        orderInfo.setReason(reason);
        orderInfo.setStatus(OrderStatus.CANCELLED);
        return orderInfoRepo.save(orderInfo);
    }

    /*
    用户取消 取消订单
     */
/*    public void cancelCancelOrder(Long orderId) {
    }*/




    /*
    支付倒计时
     */

}
