package com.izouma.dingdong.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.izouma.dingdong.domain.*;
import com.izouma.dingdong.domain.backstage.BlackList;
import com.izouma.dingdong.domain.merchant.Merchant;
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.OrderInfoDTO;
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.backstage.BlackListRepo;
import com.izouma.dingdong.repo.rider.RiderLocationRepo;
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.SalesService;
import com.izouma.dingdong.service.rider.DeliveryFeeService;
import com.izouma.dingdong.service.tencent.UserSigService;
import com.izouma.dingdong.utils.MapUtils;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
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 SalesService            salesService;
    private MerchantRepo            merchantRepo;
    private UserCouponRepo          userCouponRepo;
    private OrderRefundApplyService orderRefundApplyService;
    private RiderRepo               riderRepo;
    private DeliveryFeeService      deliveryFeeService;
    private SysConfigService        sysConfigService;
    private BlackListRepo           blackListRepo;
    private RiderLocationRepo       riderLocationRepo;
    private UserSigService          userSigService;

    /*
    用户下单
     */
    public OrderInfo userOrder(UserOrderDTO userOrderDTO) {
        //购物车
        ShoppingCart cart = shoppingCartRepo.findById(userOrderDTO.getShoppingCartId())
                .orElseThrow(new BusinessException("不存在"));

        //查找用户
        User user = userRepo.findById(cart.getUserId()).orElseThrow(new BusinessException("无用户"));
        if (user.getBlacklist()) {
            throw 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.setStatus(OrderStatus.UNPAID);
        orderInfo.setEnabled(true);
//        orderInfo.setGoodsAmount(cart.getRealAmount().subtract(cart.getDeliveryAmount()));

        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        String localTime = df.format(LocalDateTime.now());
        orderInfo.setOrderNo(user.getId() + localTime);

        //如果未设置预计到达为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());
        //获取范围
        if (distance > sysConfigService.getRange()) {
            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 (PayMethod.CASH_DELIVERY.equals(userOrderDTO.getPayMethod())) {
            if (user.getNotOrder() == -1) {
                throw new BusinessException("不可以使用货到付款");
            } else if (user.getNotOrder() != 0 && user.getNotOrder() != -1) {
                List<OrderInfo> orderInfos = orderInfoRepo.findAllByUserId(cart.getUserId());
                orderInfos.sort((a, b) -> b.getOrderTime().compareTo(a.getOrderTime()));
                LocalDateTime orderTime = orderInfos.get(0).getOrderTime();
                if (orderTime.plusHours(user.getNotOrder()).isAfter(now)) {
                    throw new BusinessException("请稍后再点单");
                }
            }
            if (ObjectUtil.isNotNull(userOrderDTO.getUserCouponId())) {
                throw new BusinessException("货到付款不能使用优惠券");
            }
        }

        // 使用优惠券(满减优惠券)
        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()));
                    //实付商品价格
//                    orderInfo.setGoodsAmount(orderInfo.getGoodsAmount().subtract(orderInfo.getRedBag()));

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

        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);
                }
        );
        return save;

    }

    /*
    订单支付完成后
     */
    public void toCompleted(Long orderId) {
        OrderInfo orderInfo = orderInfoRepo.findById(orderId).orElseThrow(new BusinessException("无订单"));
        //设置状态已支付
        orderInfo.setStatus(OrderStatus.PAID);
        //设置商家未接单
        orderInfo.setMerchantStatus(MerchantStatus.NOT_RECEIVED);
        orderInfoRepo.save(orderInfo);

        //商家
        MerchantSettings merchantSettings = merchantSettingsRepo.findByMerchantId(orderInfo.getMerchantId())
                .orElseThrow(new BusinessException("无商家"));
        Merchant merchant = merchantRepo.findById(orderInfo.getMerchantId()).orElseThrow(new BusinessException("无商家"));
        //商家是否自动接单
        if (merchantSettings.getAutomaticOrder()) {
            merReceiveOrder(orderInfo.getId(), true);
        }

        //发送im单聊消息
        userSigService.sendSms(merchant.getUserId(), Words.ORDERS.getDescription());

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


    /*
    商家接单
     */
    public OrderInfo merReceiveOrder(Long orderId, Boolean pass) {
        OrderInfo orderInfo = orderInfoRepo.findById(orderId).orElseThrow(new BusinessException("无订单"));
        if (!OrderStatus.PAID.equals(orderInfo.getStatus())) {
            throw new BusinessException("订单状态错误");
        }
        if (pass) {
            orderInfo.setMerchantStatus(MerchantStatus.RECEIVED);
            orderInfo.setRiderStatus(RiderStatus.NOT_RECEIVED);

        } else {
            //退款流程
            OrderRefundApply apply = orderRefundApplyService.apply(orderId, RefundReason.MERCHANT_REJECTION, "商家拒单退款", null);
            orderRefundApplyService.audit(apply.getId(), true, false);

            orderInfo.setMerchantStatus(MerchantStatus.REJECTED);
            orderInfo.setCancel(true);
            orderInfo.setStatus(OrderStatus.CANCELLED);
            orderInfo.setReason(RefundReason.MERCHANT_REJECTION);
        }
        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:
                if (!RiderStatus.RECEIVED.equals(riderStatus)) {
                    throw new BusinessException("订单状态错误");
                }
                //判断是否到达商家位置
                Merchant merchant = merchantRepo.findById(orderInfo.getMerchantId())
                        .orElseThrow(new BusinessException("无商家"));
                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 CARRY_OUT:
                if (!RiderStatus.TAKE_MEAL.equals(riderStatus)) {
                    throw new BusinessException("订单状态错误");
                }
                //确认是否到达用户地址位置
                String location = orderInfo.getLocation();
                String[] split = location.split(",");
                Double latitude2 = Double.valueOf(split[0]);
                Double longitude2 = Double.valueOf(split[1]);
                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);
    }

    /*
    骑手到店拍照取货
     */
    public void pickupPhotos(Long orderId, RiderStatus status, String img) {
        OrderInfo orderInfo = orderInfoRepo.findById(orderId).orElseThrow(new BusinessException("无订单"));
        if (!RiderStatus.TAKE_MEAL.equals(status)) {
            throw new BusinessException("状态错误");
        }
        if (StrUtil.isEmpty(img)) {
            throw new BusinessException("照片不能为空");
        }
        if (!RiderStatus.ARRIVE.equals(orderInfo.getRiderStatus())) {
            throw new BusinessException("订单状态错误");
        }
        //已取餐 待送达
        orderInfo.setRiderStatus(RiderStatus.TAKE_MEAL);
        //商家状态已完成
        orderInfo.setMerchantStatus(MerchantStatus.CARRY_OUT);
        orderInfo.setPickupPhotos(img);
        orderInfoRepo.save(orderInfo);
    }

    /*
    骑手强制已到店，已送达
    */
    public void mandatory(Long orderId, RiderStatus status) {
        OrderInfo orderInfo = orderInfoRepo.findById(orderId).orElseThrow(new BusinessException("无订单"));
        switch (status) {
            case ARRIVE:
                //待取餐
                orderInfo.setRiderStatus(RiderStatus.ARRIVE);
                orderInfoRepo.save(orderInfo);
                return;
            case CARRY_OUT:
                //已送达
                orderInfo.setRiderStatus(RiderStatus.CARRY_OUT);
                orderInfo.setUserReceivedTime(LocalDateTime.now());
                orderInfo.setStatus(OrderStatus.RATED);

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

    /*
    用户取消订单
     */
    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);

        }

        //发送im单聊消息
        Long muserId = merchantRepo.findById(orderInfo.getMerchantId())
                .orElseThrow(new BusinessException("无商家"))
                .getUserId();
        userSigService.sendSms(muserId, Words.CANCEL.getDescription());

        //如果是货到付款
        if (PayMethod.CASH_DELIVERY.equals(orderInfo.getPayMethod())) {
            this.cancelCashOrder(id);
        }

        //订单待评价/已完成
        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);
                }
            }
        }
        if (orderInfo.getRiderId() != null) {
            //发送im单聊消息
            Long ruserId = riderRepo.findById(orderInfo.getRiderId())
                    .orElseThrow(new BusinessException("无骑手"))
                    .getUserId();
            userSigService.sendSms(ruserId, Words.CANCEL.getDescription());
        }

        // orderInfo.setCancel(true);
        orderInfo.setReason(reason);
        orderInfo.setStatus(OrderStatus.CANCELLED);
        return orderInfoRepo.save(orderInfo);
    }

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


    /*
    支付倒计时
     */

    /*
    货到付款取消订单
     */
    public void cancelCashOrder(Long orderId) {
        OrderInfo orderInfo = orderInfoRepo.findById(orderId).orElseThrow(new BusinessException("无订单"));
        //已送达
        RiderStatus riderStatus = orderInfo.getRiderStatus();
        if (RiderStatus.CARRY_OUT.equals(riderStatus)) {
            throw new BusinessException("已送达，不可取消");
        }

        //取消订单
        orderInfo.setCancel(true);
        orderInfo.setStatus(OrderStatus.CANCELLED);

        //骑手已接单，已到店，正在配送
        //用户n小时不可下单
        if (RiderStatus.RECEIVED.equals(riderStatus)
                || RiderStatus.ARRIVE.equals(riderStatus)
                || RiderStatus.TAKE_MEAL.equals(riderStatus)) {

            //查出用户所有的订单信息，按时间倒叙
            List<OrderInfo> infos = orderInfoRepo.findAllByUserId(orderInfo.getUserId());
            infos.sort((a, b) -> b.getOrderTime().compareTo(a.getOrderTime()));
            //连续次数
            int times = 1;
            for (OrderInfo i : infos) {
                if (!i.getCancel() && !PayMethod.CASH_DELIVERY.equals(i.getPayMethod())) {
                    break;
                }
                times++;
            }
            //找出用户
            User user = userRepo.findById(orderInfo.getUserId()).orElseThrow(new BusinessException("无用户"));
            if (times == 2) {
                user.setNotOrder(1);
            } else if (times == 3) {
                user.setNotOrder(24);
            } else if (times >= 4) {
                user.setNotOrder(-1);
                user.setBlacklist(true);
                //拉入黑名单
                blackListRepo.save(BlackList.builder()
                        .userId(user.getId())
                        .otherId(user.getId())
                        .remove(false)
                        .moveTime(LocalDateTime.now())
                        .reason("连续四次货到付款取消订单")
                        .identity(Identity.USER)
                        .enabled(true)
                        .build());
            }
            userRepo.save(user);
        }
    }

    public OrderInfoDTO toDto(OrderInfo orderInfo) {
        OrderInfoDTO dto = new OrderInfoDTO();
        BeanUtil.copyProperties(orderInfo, dto);
        Long riderId = orderInfo.getRiderId();
        if (riderId != null) {
            riderRepo.findById(riderId).ifPresent(rider -> {
                dto.setJobNumber(rider.getJobNumber());
                dto.setRiderName(rider.getUser().getNickname());
                dto.setRuserId(rider.getUserId());
            });
            riderLocationRepo.findLastByRiderId(riderId)
                    .ifPresent(lo ->
                            dto.setLocation(lo.getLongitude() + "," + lo.getLatitude()));

        }
        dto.setNickname(orderInfo.getUser().getNickname());
//        userRepo.findById(orderInfo.getUserId()).ifPresent(u -> dto.setNickname(u.getNickname()));
//        dto.setMerchantShowName(orderInfo.getMerchant().getShowName());
        merchantRepo.findById(orderInfo.getMerchantId()).ifPresent(merchant -> {
            dto.setMerShowName(merchant.getShowName());
            dto.setMerLocation(merchant.getLongitude() + "," + merchant.getLatitude());
            dto.setMerAddress(merchant.getAddress());
            dto.setMid(merchant.getId());
            dto.setMerLogo(merchant.getLogo());
            dto.setMuserId(merchant.getUserId());
        });

        return dto;
    }
}
