package com.izouma.dingdong.service.rider;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
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.rider.RiderSign;
import com.izouma.dingdong.dto.RiderDTO;
import com.izouma.dingdong.dto.RiderDistanceDTO;
import com.izouma.dingdong.enums.*;
import com.izouma.dingdong.exception.BusinessException;
import com.izouma.dingdong.repo.MoneyRecordRepo;
import com.izouma.dingdong.repo.OrderInfoRepo;
import com.izouma.dingdong.repo.SysConfigRepo;
import com.izouma.dingdong.repo.UserRepo;
import com.izouma.dingdong.repo.rider.RiderRepo;
import com.izouma.dingdong.repo.rider.RiderSignRepo;
import com.izouma.dingdong.service.OrderRefundApplyService;
import com.izouma.dingdong.utils.MapUtils;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

@Service
@AllArgsConstructor
public class RiderService {

    private RiderRepo               riderRepo;
    private UserRepo                userRepo;
    private MoneyRecordRepo         moneyRecordRepo;
    private OrderInfoRepo           orderInfoRepo;
    private OrderRefundApplyService orderRefundApplyService;
    private RiderSignRepo           riderSignRepo;
    private SysConfigRepo           sysConfigRepo;


    /*
    骑手注册
     */
    public Rider riderApply(RiderDTO riderDTO) {
        userRepo.findById(riderDTO.getUserId()).orElseThrow(new BusinessException("无用户"));
        Rider rider = new Rider();
        BeanUtil.copyProperties(rider, riderDTO);
        rider.setBlacklist(false);
        rider.setEnabled(true);
        //rider.setSignIn(false);
        rider.setStatus(ApplyStatus.PENDING);
        return riderRepo.save(rider);
    }

    /*
    骑手审核
     */
    public String riderAudit(Long riderId, Boolean pass, String reason) {
        Rider rider = riderRepo.findById(riderId).orElseThrow(new BusinessException("无骑手"));
        if (pass) {
            rider.setStatus(ApplyStatus.PASS);
            //boolean i = true;
            while (true) {
                //随机生成骑手工号 一个首字母+四个数字
                String jobNumber1 = RandomStringUtils.randomAlphabetic(1);
                String jobNumber2 = RandomStringUtils.randomNumeric(4);
                String jobNumber = jobNumber1 + jobNumber2;
                Rider byJobNumber = riderRepo.findByJobNumber(jobNumber);
                if (ObjectUtil.isNull(byJobNumber)) {
                    rider.setJobNumber(jobNumber);
                    //i = false;
                    riderRepo.save(rider);
                    return jobNumber;
                }
            }
        } else {
            rider.setStatus(ApplyStatus.DENY);
            riderRepo.save(rider);
            return reason;
        }
    }


    /*
    骑手签到
     */
    public void sign(Long riderId, String password, Double longitude, Double latitude) {
        Rider rider = riderRepo.findById(riderId).orElseThrow(new BusinessException("无骑手"));
        Double distance = MapUtils.distance(longitude, latitude, rider.getLongitude(), rider.getLatitude());
        String range = sysConfigRepo.findByName("range").orElseThrow(new BusinessException("无配置")).getValue();
        if (distance > new Double(range)) {
            throw new BusinessException("不在工作区域");
        }
        User user = userRepo.findById(rider.getUserId()).orElseThrow(new BusinessException("无用户"));
        boolean matches = new BCryptPasswordEncoder().matches(password, user.getPassword());
        if (!matches) {
            throw new BusinessException("密码不正确");
        }
        riderSignRepo.save(RiderSign.builder()
                .latitude(latitude)
                .longitude(longitude)
                .riderId(riderId)
                .signTime(LocalDateTime.now())
                .build());
    }

    /**
     * 骑手收入，且保存到记录表
     *
     * @param riderId    骑手ID
     * @param fromUserId 来自用户
     * @param amount     金额
     * @param type       流水类型
     * @param remark     备注
     */
    public void income(Long riderId, Long fromUserId, BigDecimal amount, FinancialType type, String remark) {
        //骑手应得  riderRepo.findUserIdById(riderId)
        User riderUser = userRepo.findById(riderId).orElseThrow(new BusinessException("无用户"));
        riderUser.setMoney(riderUser.getMoney().add(amount));
        userRepo.save(riderUser);

        //购买的user
        User user = userRepo.findById(fromUserId).orElseThrow(new BusinessException("无用户"));

        moneyRecordRepo.save(MoneyRecord.builder()
                .amount(amount)
                .avatar(user.getAvatar())
                .name(user.getNickname())
                .type(type)
                .fromUserId(fromUserId)
                .userId(riderUser.getId())
                .time(LocalDateTime.now())
                .remark(remark)
                .enabled(true)
                .build());
    }


    /*
    骑手抢单形式接单
    5分钟内手动抢单
     */
    public void riderReceiveOrder(Long riderId, Long orderId, Boolean pass) {
        OrderInfo orderInfo = orderInfoRepo.findById(orderId).orElseThrow(new BusinessException("无订单"));

        if (pass) {
            if (!OrderStatus.PAID.equals(orderInfo.getStatus())) {
                throw new BusinessException("订单不可接单");
            }
            if (!MerchantStatus.RECEIVED.equals(orderInfo.getMerchantStatus())) {
                throw new BusinessException("商家未接单");
            }
            if (!RiderStatus.NOT_RECEIVED.equals(orderInfo.getRiderStatus())) {
                throw new BusinessException("已被其他骑手接单");
            }

            List<OrderInfo> infos = orderInfoRepo.findAllByRiderIdAndRiderStatusIsNot(riderId, RiderStatus.CARRY_OUT);
            if (infos.size() >= 5) {
                throw new BusinessException("未完成订单已达上线");
            }
            //设置订单状态
            orderInfo.setRiderId(riderId);
            orderInfo.setRiderStatus(RiderStatus.RECEIVED);
//            orderInfo.setRiderOrderTime(LocalDateTime.now());
            orderInfoRepo.save(orderInfo);
        }
    }

    /*
    系统派单
    5分钟后自动接单
        有空闲骑手离商家最近的距离排序，骑手不可拒单
        无空闲，离商家最近的3个骑手，订单量少的接单
        订单量相同，距离最近接单
        商家3km内无骑手，取消订单
     */
    public void dispatch(Long orderId, List<RiderDistanceDTO> dtos) {
        OrderInfo orderInfo = orderInfoRepo.findById(orderId).orElseThrow(new BusinessException("无订单"));
        Map<Long, Double> map = new HashMap<>();
        dtos.forEach(d -> {
            Merchant merchant = orderInfo.getMerchant();
            Double distance = MapUtils.distance(merchant.getLongitude(), merchant.getLatitude(), d.getLongitude(), d.getLatitude());
            map.put(d.getRiderId(), distance);
        });

        //无骑手，取消订单
        if (CollUtil.isEmpty(map)) {
//            orderInfoService.cancel(orderId, RefundReason.UNABLE_TO_DELIVER, null, null);
            OrderRefundApply apply = orderRefundApplyService.apply(orderId, RefundReason.UNABLE_TO_DELIVER, null, null);
            orderRefundApplyService.audit(apply.getId(), true, false);
            return;
        }

        //排序
        List<Map.Entry<Long, Double>> list = new ArrayList<>(map.entrySet());
        list.sort(Comparator.comparing(Map.Entry<Long, Double>::getValue));

        for (Map.Entry<Long, Double> m : list) {
            Rider rider = riderRepo.findById(m.getKey()).orElseThrow(new BusinessException("无骑手"));
            //if (rider.getSignIn()) {
            List<OrderInfo> infos = orderInfoRepo.findAllByRiderIdAndRiderStatusIsNot(m.getKey(), RiderStatus.CARRY_OUT);
            //有空闲骑手，自动接单，不可拒单
            if (CollUtil.isEmpty(infos)) {
                //riderId = m.getKey();
                orderInfo.setRiderId(m.getKey());
                orderInfo.setRiderStatus(RiderStatus.RECEIVED);
                orderInfoRepo.save(orderInfo);
                return;
                //break;
            }
            //}
        }

        //无空闲骑手，未完成订单最少的接单
        int infos1 = orderInfoRepo.findAllByRiderIdAndRiderStatusIsNot(list.get(0)
                .getKey(), RiderStatus.CARRY_OUT).size();
        int infos2 = orderInfoRepo.findAllByRiderIdAndRiderStatusIsNot(list.get(1)
                .getKey(), RiderStatus.CARRY_OUT).size();
        int infos3 = orderInfoRepo.findAllByRiderIdAndRiderStatusIsNot(list.get(2)
                .getKey(), RiderStatus.CARRY_OUT).size();
        Long riderId = null;
        if (infos1 < infos2 && infos1 < infos3) {
            riderId = list.get(0).getKey();
        } else if (infos2 < infos1 && infos2 < infos3) {
            riderId = list.get(1).getKey();
        } else if (infos3 < infos1 && infos3 < infos2) {
            riderId = list.get(2).getKey();
        }
        if (riderId != null) {
            orderInfo.setRiderId(riderId);
            orderInfo.setRiderStatus(RiderStatus.RECEIVED);
            orderInfoRepo.save(orderInfo);
            return;
        }

        //无空闲骑手 距离最近的接单
        if (RiderStatus.NOT_RECEIVED.equals(orderInfo.getRiderStatus())) {
            riderId = list.get(0).getKey();
            orderInfo.setRiderId(riderId);
            orderInfo.setRiderStatus(RiderStatus.RECEIVED);
        }

        orderInfoRepo.save(orderInfo);
    }


}
