package com.leromro.core.service.impl;

import cn.hutool.core.lang.Snowflake;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.service.WxPayService;
import com.leromro.common.constant.CommonConstants;
import com.leromro.common.core.domain.ListPermission;
import com.leromro.common.core.domain.R;
import com.leromro.common.core.domain.entity.SysDept;
import com.leromro.common.core.domain.entity.SysUser;
import com.leromro.common.exception.ServiceException;
import com.leromro.common.utils.GeoUtils;
import com.leromro.common.utils.SecurityUtils;
import com.leromro.core.domain.*;
import com.leromro.core.domain.dto.OrderRequestDTO;
import com.leromro.core.domain.dto.WebMainOrdersDTO;
import com.leromro.core.domain.vo.*;
import com.leromro.core.mapper.*;
import com.leromro.core.service.IMainOrderService;
import com.leromro.core.service.IOrderSettlementApplicationService;
import com.leromro.core.utils.BigDecimalUtil;
import com.leromro.core.utils.DateTimeUtil;
import com.leromro.core.utils.JsonParser;
import com.leromro.core.utils.NoUtil;
import com.leromro.system.mapper.SysDeptMapper;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class MainOrderServiceImpl extends ServiceImpl<MainOrdersMapper, MainOrders> implements IMainOrderService{
    @Autowired
    private MainOrdersMapper mainOrdersMapper;
    @Autowired
    private SecondOrdersMapper secondOrdersMapper;
    @Autowired
    private ClientAccountMapper clientAccountMapper;
    @Autowired
    private VolunteerWorkDateMapper workDateMapper;
    @Autowired
    private VolunteerReservationTimeServiceImpl volunteerReservationTimeService;
    @Autowired
    private VolunteerInfoMapper volunteerInfoMapper;
    @Autowired
    private Snowflake snowflake;
    @Autowired
    private PlatformFinanceMapper platformFinanceMapper;
    @Autowired
    private AddressMapper addressMapper;
    @Autowired
    private ClientAccountChangeMapper clientAccountChangeMapper;

    @Autowired
    @Qualifier("wxMiniPayService")
    private WxPayService wxMiniPayService;
    @Autowired
    private IOrderSettlementApplicationService iOrderSettlementApplicationService;

    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private SysDeptMapper sysDeptMapper;

    @Autowired
    private DeptRegionManagementMapper deptRegionManagementMapper;

    /**
     * @param userId
     * @return
     */
    @Override
    public List<MainOrdersVO> selectByUserId(String[] orderStatus, Long userId) {

        List<MainOrdersVO> ordersVOS = mainOrdersMapper.selectByUserId(orderStatus,userId);
        return  ordersVOS;
    }



    /**
     * @param orderRequest
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R<OrderPaymentVO> createOrders(OrderRequestDTO orderRequest) throws Exception {
        //响应数据
        OrderPaymentVO vo = new OrderPaymentVO();
        //订单信息
        MainOrders orders = orderRequest.getOrders();
        if (SecurityUtils.getUserId().equals(orders.getVolunteerId())){
            throw new RuntimeException("不可以给自己下单");
        }
        //由于前端传过来的不是有序的，所以我们要将工作时间进行排序
        List<VolunteerWorkDate> workDateList = orderRequest.getWorkDateList()
                .stream()
                .sorted(Comparator.comparing(VolunteerWorkDate::getWorkDate))
                .collect(Collectors.toList());
        Long userId = SecurityUtils.getUserId();
        //主键id
        long orderId = snowflake.nextId();
        vo.setMainOrderId(orderId);
        //订单号
        String orderNo = NoUtil.getOrderNo();
        orders.setOutTradeNo(orderNo);


        //获取志愿者信息，同时服务时长和价格也都在志愿者id中进行获取
        VolunteerInfo info = volunteerInfoMapper.selectOne(new LambdaQueryWrapper<VolunteerInfo>()
                .eq(VolunteerInfo::getVolunteerInfoId, orders.getVolunteerInfoId()));
        /** 商品数量单价金额信息*/
        BigDecimal serviceOnePrice = info.getBusinessPrice();
        Integer businessDurationMin = info.getBusinessDuration();
        Long totalTimes = orders.getTotalTimes();
        Long singleQuantity = orders.getSingleQuantity();
        //总价 = 服务单词价格*服务次数*单词服务数量
        BigDecimal totalPrice = serviceOnePrice.multiply(BigDecimal.valueOf(totalTimes)).multiply(BigDecimal.valueOf(singleQuantity));
        orders.setServiceTotalPrice(totalPrice);
        // 判断支付方式，余额扣减余额。 1 余额 2 微信
        String seconderStatus;
        if (orders.getPaymentMethod().equals("1")){
            // 查看余额够不够  修改用户余额表
            ClientAccount clientAccount = clientAccountMapper.selectBalanceByuserID(userId);
            BigDecimal balanceOld = clientAccount.getBalance();
            BigDecimal newBalance = balanceOld.subtract(totalPrice);
            if (newBalance.compareTo(BigDecimal.ZERO) < 0){
                throw new RuntimeException("余额不足,支付失败");
            }else {
                BigDecimal balanceNew = balanceOld.subtract(totalPrice);
                clientAccount.setBalance(balanceNew);
                clientAccount.setUpdateTime(DateTimeUtil.getNowTime());
                clientAccountMapper.updateClientBalance(clientAccount);
            }
            // 余额足够 直接支付 订单状态为已支付
            orders.setOrderStatus("1");
            seconderStatus = "1";
            //向钱包变更记录表中新增 一条购买的数据
            ClientAccountChange clientAccountChange = ClientAccountChange.builder().userId(userId).changeType("0").sourceType("1").changeMoney(totalPrice).beforeBalance(balanceOld).afterBalance(newBalance).mainOrderId(orderId).build();
            clientAccountChange.setCreateTime(DateTimeUtil.getNowTime1());
            clientAccountChangeMapper.insert(clientAccountChange);
        }else if (orders.getPaymentMethod().equals("2")){
           /**微信支付 */
            //组装微信预下单参数
            try {
                seconderStatus = "1";
                WxPayUnifiedOrderRequest orderReq = new WxPayUnifiedOrderRequest();
                orderReq.setOutTradeNo(orderNo);
                //单位分
                orderReq.setTotalFee(BigDecimalUtil.yuanToFee(totalPrice));
                SysUser user = SecurityUtils.getLoginUser().getUser();
                orderReq.setOpenid(user.getUserOpenId());
                orderReq.setBody("微信支付");
                orderReq.setSpbillCreateIp(user.getLoginIp());
                log.info("【微信支付】预下单开始，参数={}", orderReq);
                WxPayMpOrderResult result = wxMiniPayService.createOrder(orderReq);
                if (result == null) {
                    throw new ServiceException();
                }
                vo.setTimeStamp(result.getTimeStamp());
                vo.setNonceStr(result.getNonceStr());
                vo.setPackageValue(result.getPackageValue());
                vo.setSignType(result.getSignType());
                vo.setPaySign(result.getPaySign());
                log.info("【微信支付】预下单成功，结果={}", result);
            }catch (Exception e){
                log.error("【微信支付】支付失败 原因={}", e.getMessage());
                return R.fail("服务器繁忙，暂时无法下单，请稍后再试");
            }

            //设置订单支付状态
            orders.setOrderStatus("0");
            seconderStatus = "0";
        }else {
            throw new RuntimeException("支付方式错误");
        }
        //创建订单主表
        //把地址信息也添加到数据里面
        Address address = addressMapper.selectAddressByAddressId(orders.getAddressId());



        //地址拼接信息+经纬度
        String OrderAddress = String.join("",
                Objects.toString(address.getProvinceName(), ""),
                Objects.toString(address.getCityName(), ""),
                Objects.toString(address.getDistrictName(), ""),
                Objects.toString(address.getAddress(), ""));
        orders.setAddressLongitude(address.getLongitude());
        orders.setAddressLatitude(address.getLatitude());
        orders.setAddress(OrderAddress);
        orders.setClientName(address.getName());
        orders.setClientTelephone(address.getTelephone());
        orders.setProvinceName(address.getProvinceName());
        orders.setProvinceCode(address.getProvinceCode());
        orders.setCityName(address.getCityName());
        orders.setCityCode(address.getCityCode());
        orders.setDistrictName(address.getDistrictName());
        orders.setDistrictCode(address.getDistrictCode());

        orders.setMainOrderId(orderId);
        orders.setServiceDuration(info.getBusinessDuration());
        orders.setFinishTimes(0L);
        orders.setUserId(userId);
        orders.setCreateTime(DateTimeUtil.getNowTime());
        orders.setServiceOnePrice(serviceOnePrice);
        orders.setServiceTotalPrice(totalPrice);
        orders.setServiceDuration(businessDurationMin);
        //设置服务的开始与结束日期 以及开始与结束时间
        orders.setServiceStartDate(workDateList.get(0).getWorkDate());
        orders.setServiceFinishDate(workDateList.get(workDateList.size()-1).getWorkDate());
        this.save(orders);

        //修改志愿者预约时间表
        VolunteerReservationTime reservationTime =VolunteerReservationTime.builder().volunteerId(orders.getVolunteerId()).clientId(userId).build();
        reservationTime.setRemark(orders.getRemark());
        List<VolunteerReservationTime> reservationTimes = new ArrayList<>();

        //创建小订单模板
        SecondOrder secondOrder = SecondOrder.builder().mainOrderId(orderId).volunteerId(orders.getVolunteerId()).singleQuantity(singleQuantity)
                .serviceCategory(orders.getServiceCategory()).serviceDuration(orders.getServiceDuration()).addressId(orders.getAddressId()).serviceTotalPrice(serviceOnePrice.multiply(BigDecimal.valueOf(orders.getSingleQuantity())))
                .serviceOnePrice(orders.getServiceOnePrice()).volunteerInfoId(orders.getVolunteerInfoId()).orderStatus(seconderStatus)
                .provinceCode(address.getProvinceCode()).cityCode(address.getCityCode()).districtCode(address.getDistrictCode())
                .provinceName(address.getProvinceName()).cityName(address.getCityName()).districtName(address.getDistrictName())
                .longitude(address.getLongitude()).latitude(address.getLatitude())
                .address(address.getAddress()).areaSettlementStatus("10").volunteerSettlementStatus("10").serviceCentreSettlementStatus("10")
                .secondOrderCreateTime(DateTimeUtil.getNowTime())
                .outTradeNo(orderNo)
                .build();
        secondOrder.setRemark(orders.getRemark());
        //根据下单的收货地址，来设置分账比例 先查这个订单是否在电子围栏中
        //找到所有的部门的数据，然后把所有的数据遍历，并且统计出来
        //用的是新版的部门区域  但是获取分账比例还是从老的中获取
       /* List<DeptRegionManagement> deptRegionManagements = deptRegionManagementMapper.selectList(new LambdaQueryWrapper<DeptRegionManagement>().eq(DeptRegionManagement::getDelFlag, 2));
        List<Long> deptIdsList = deptRegionManagements.stream().map(DeptRegionManagement::getDeptId).collect(Collectors.toList());*/

        List<SysDept> sysDepts = sysDeptMapper.getAlldept();

        List<Long> deptIdList = new ArrayList<>();
        /*for (DeptRegionManagement deptRegionManagement : deptRegionManagements) {}*/
        for (SysDept sysDept : sysDepts) {
            //判断 服务中心分成比例
            //真的
            /* String pointList = sysDept.getPointList();
            boolean insidePolygon ;
            if (pointList != null){
                List<double[]> doubles = JsonParser.parseCoordinates(pointList);
                 insidePolygon = GeoUtils.isInsidePolygon(Double.parseDouble(address.getLatitude()) , Double.parseDouble(address.getLongitude()), doubles);
            }else {
                insidePolygon = false;
            }
            if (insidePolygon){
                //如果是true  将这个地址的区域id添加到集合中
                deptIdList.add(sysDept.getDeptId());
            }//如果false 则什么都不变*/
            //区域公司的分成比例 因为没有区域公司，也不会有志愿者，所以这个区域公司一定会匹配上的
            if (sysDept.getDistrictCode()== null){
                continue;
            }
            if (sysDept.getDistrictCode().equals(address.getDistrictCode()) && sysDept.getAreaType().equals("3")){
                secondOrder.setAreaDistributionRatio(sysDept.getDistributionRatio());
                secondOrder.setAreaDistributionId(sysDept.getDeptId());
                orders.setAreaDistributionId(sysDept.getDeptId());
            }
        }

        //根据匹配数量，修改数值,（开会说不用电子围栏）
       /* if (deptIdList.size()==1){
            //已分配到服务中心
            secondOrder.setAllotStatus("20");
            secondOrder.setServiceCenterId(deptIdList.get(0));
            //设置服务中心的分成比例
            sysDepts.forEach(sysDept -> {
                if (sysDept.getDeptId().equals(deptIdList.get(0)) && sysDept.getAreaType().equals("10")) {
                    secondOrder.setServiceCentreDistributionRatio(sysDept.getDistributionRatio());
                    secondOrder.setServiceCenterId(sysDept.getDeptId());
                }
            });

        } else {

        }*/

        secondOrder.setAllotStatus("10");
        List<SecondOrder> secondOrderList = new ArrayList<>();


        //workDate 去计算 更新有预约 为1
        //修改志愿者预约时间表以及新增志愿者预约时间
        long number = 1;
        //
        List<VolunteerWorkDate> volunteerWorkDates = new ArrayList<>();
        //小订单id集合
        List<Long> seconderIdList = new ArrayList<>();
        for (VolunteerWorkDate workDate : workDateList) {
            //向secondOrder中添加数据
            long secondOrderIdL = snowflake.nextId();
            seconderIdList.add(secondOrderIdL);
            SecondOrder secondOrder1 = new SecondOrder();
            BeanUtils.copyProperties(secondOrder,secondOrder1);
            secondOrder1.setWorkDate(workDate.getWorkDate());
            secondOrder1.setWorkStartTime(workDate.getWorkStartTime());
            secondOrder1.setWorkEndTime(workDate.getWorkStartTime().plus(Duration.ofMinutes(orders.getServiceDuration()*orders.getSingleQuantity())));
            secondOrder1.setWorkNumber(number);
            secondOrder1.setSecondOrderId(secondOrderIdL);
            String orderNoId = orderNo+"-"+number;
            secondOrder1.setOutTradeNo(orderNoId);
            secondOrderList.add(secondOrder1);

            //向志愿者预约时间表中添加数据
            int parts = (int) (businessDurationMin * singleQuantity /30);
            if (businessDurationMin % 30!=0){
                parts++;
            }
            LocalTime workStartTime = workDate.getWorkStartTime();
            for (int i = 0; i < parts; i++) {
                VolunteerReservationTime reservationTime1 = new VolunteerReservationTime();
                BeanUtils.copyProperties(reservationTime,reservationTime1);
                reservationTime1.setReservationDate(workDate.getWorkDate());
                reservationTime1.setReservationTime(workStartTime);
                reservationTimes.add(reservationTime1);
                workStartTime = workStartTime.plusMinutes(30);
            }
            number++;
            workDate.setVolunteerId(orders.getVolunteerId());
            LocalTime workEndTime = workDate.getWorkStartTime().plus(Duration.ofHours(orders.getServiceDuration()));
            workDate.setWorkEndTime(workEndTime);
            workDate.setHasReservation(1);
            workDate.setUpdateTime(DateTimeUtil.getNowTime());
            volunteerWorkDates.add(workDate);
        }

        //调用方法，向平台流水中添加数据
        if(!orders.getOrderStatus().equals("0")){
            // 0 是待支付，
            changePlatformFinance(seconderIdList,orders);
        }


        //新增志愿者订单小表N个  得修改这种
        secondOrdersMapper.insertList(secondOrderList);
        //新增志愿者预约时间表
        volunteerReservationTimeService.insertVolunteerReservationTimeList(reservationTimes);

      //修改志愿者排班日期表
        workDateMapper.updateVolunteerWorkDatebyVolunteerId(volunteerWorkDates);

        return R.ok(vo);
    }


    @Override
    public List<webMainOrderListVO> webMainOrderList(WebMainOrdersDTO dto) {
        //区分服务中心
        if (SecurityUtils.getAreaType().equals("4")){
            dto.setDeptId(SecurityUtils.getDeptId());
        }
        List<webMainOrderListVO> vos = baseMapper.webMainOrderList(new ListPermission(MainOrders.class, CommonConstants.CHECK_PROVINCE_CITY_DISTRICT) ,dto);
        return vos;
    }

    /**
     * @param secondOrderId
     */
    @Override
    public void startService(Long secondOrderId) {
        mainOrdersMapper.startService(secondOrderId);
    }

    /**
     * @param mainOrderId
     * @return
     */
    @Override
    public WebMainOrdersInfoVO selectWebMainOrderInfoVO(Long mainOrderId) {
        WebMainOrdersInfoVO webMainOrderInfoVO = mainOrdersMapper.selectWebMainOrderInfoVO(mainOrderId);
        return webMainOrderInfoVO;
    }

    public void changePlatformFinance ( List<Long> seconderIdList,MainOrders orders){
        //创建平台流水模板  按照小订单，单价*件数 = 小订单价格 = 一条平台流水变动
        PlatformFinance platformFinance =  PlatformFinance.builder().changeMoney(orders.getServiceOnePrice().multiply(BigDecimal.valueOf(orders.getSingleQuantity()))).changeType(1).moneyType(1)
                .sourceType(1).volunteerId(orders.getVolunteerId()).build();
        platformFinance.setCreateTime(DateTimeUtil.getNowTime());
        List<PlatformFinance> platformFinanceList = new ArrayList<>();
        for (Long seconderId : seconderIdList) {
            //向平台流水中添加数据
            PlatformFinance platformFinance1 = new PlatformFinance();
            BeanUtils.copyProperties(platformFinance,platformFinance1);
            platformFinance1.setSecondOrderId(seconderId);
            platformFinanceList.add(platformFinance1);
        }
        //新增公司资金流水表N个
        platformFinanceMapper.insertPlatformFinanceList(platformFinanceList);
    }

    /**
     * @param mainOrderId
     * @return
     */
    @Override
    public MainOrderInfoVO selectOrderInfoByUserId(Long mainOrderId) {
        MainOrderInfoVO mainOrderInfoVO = mainOrdersMapper.selectOrderInfoByUserId(mainOrderId);
        return mainOrderInfoVO;
    }
}
