package com.izouma.jiashanxia.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.izouma.jiashanxia.domain.*;
import com.izouma.jiashanxia.domain.Package;
import com.izouma.jiashanxia.dto.OrderInfoVO;
import com.izouma.jiashanxia.dto.PackageGoodsDTO;
import com.izouma.jiashanxia.dto.PageQuery;
import com.izouma.jiashanxia.enums.OrderInfoStatus;
import com.izouma.jiashanxia.enums.PayMethod;
import com.izouma.jiashanxia.enums.TransactionType;
import com.izouma.jiashanxia.exception.BusinessException;
import com.izouma.jiashanxia.repo.*;
import com.izouma.jiashanxia.utils.JpaUtils;
import lombok.AllArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.Predicate;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;


@Service
@AllArgsConstructor
public class OrderInfoService {

    private OrderInfoRepo        orderInfoRepo;
    private PackageRepo          packageRepo;
    private PackageGoodsRepo     packageGoodsRepo;
    private UserRepo             userRepo;
    private SysConfigService     sysConfigService;
    private CommissionRecordRepo commissionRecordRepo;
    private UserPackageService   userPackageService;
    private CompanyRepo          companyRepo;
    private WithdrawService      withdrawService;

    public Page<OrderInfo> all(PageQuery pageQuery) {
        pageQuery.setSort("createdAt,desc");
        return orderInfoRepo.findAll(JpaUtils.toSpecification(pageQuery, OrderInfo.class), JpaUtils.toPageRequest(pageQuery));
    }

    /*
    后台列表
     */
    public Page<OrderInfo> backAll(PageQuery pageQuery) {
        pageQuery.setSort("createdAt,desc");
        return orderInfoRepo.findAll(((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> and = JpaUtils.toPredicates(pageQuery, OrderInfo.class, root, criteriaQuery, criteriaBuilder);
            if (StrUtil.isNotEmpty(pageQuery.getSearch())) {
                withdrawService.getNickname(pageQuery.getSearch(), and, root, criteriaBuilder);
            }
            return criteriaBuilder.and(and.toArray(new Predicate[0]));
        }), JpaUtils.toPageRequest(pageQuery));
    }

    /*
    下订单
     */
    public OrderInfo createOrder(Long userId, Long packageId, PayMethod payMethod) {
        Package setInfo = packageRepo.findById(packageId).orElseThrow(new BusinessException("无套餐"));
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        String localTime = df.format(LocalDateTime.now());
        String num = String.format("%05d", orderInfoRepo.orderNum() + 1);

        OrderInfo order = OrderInfo.builder()
                .packageId(packageId)
                .status(OrderInfoStatus.UNPAID)
                .userId(userId)
                .payMethod(payMethod)
                .orderNumber(localTime + num)
                .price(setInfo.getAmount())
                .name(setInfo.getName())
                .num(1)
                .build();
        return orderInfoRepo.save(order);
    }

    /*
    完成付款
     */
    public void completed(Long orderInfoId, String transactionId) {
        // 修改订单状态
        OrderInfo order = orderInfoRepo.findById(orderInfoId).orElseThrow(new BusinessException("无订单"));
        order.setStatus(OrderInfoStatus.PAID);
        order.setTransactionId(transactionId);
        order.setPaidAt(LocalDateTime.now());
        orderInfoRepo.save(order);

        // 套餐内商品
        List<PackageGoods> setGoodsList = packageGoodsRepo.findAllByPackageId(order.getPackageId());
        // 用户
        Long userId = order.getUserId();
        User user = userRepo.findById(userId).orElseThrow(new BusinessException("无用户"));
        // 设置用户为vip
        if (!user.isVip()) {
            user.setVip(true);
            userRepo.save(user);
        }
        // 加入套餐商品
        userPackageService.joinUserPackage(userId, setGoodsList, 1);

        // 用户id和上级id相同
        if (user.getParent() != null && !userId.equals(user.getParent())) {
            // 上级分销
            this.distribution(userId, user.getParent(), transactionId);
        }
    }

    /*
    取消订单
     */
    public OrderInfo cancelOrder(Long orderId) {
        OrderInfo orderInfo = orderInfoRepo.findById(orderId).orElseThrow(new BusinessException("无订单"));
        if (OrderInfoStatus.PAID.equals(orderInfo.getStatus())) {
            throw new BusinessException("订单已支付，无法取消");
        } else if (OrderInfoStatus.CANCELLED.equals(orderInfo.getStatus())) {
            return orderInfo;
        }
        orderInfo.setStatus(OrderInfoStatus.CANCELLED);
        return orderInfoRepo.save(orderInfo);
    }

    /*
    分销
    又有团队，员工自己又购买了套餐，企业是否有收益？
    企业拉员工，员工的上级是否改为企业领导人？
    如果上级和企业不是一个人，收益如何算？
     */
    public void distribution(Long userId, Long parent, String transactionId) {
        User parentUser = userRepo.findById(parent).orElseThrow(new BusinessException("无用户"));
        // 判断是否可分享
        boolean flag = false;
        // 是否公司员工
        if (ObjectUtil.isNotEmpty(parentUser.getCompanyId())) {
            flag = true;
            // 公司可得分销
            this.companyDis(parentUser.getCompanyId(), transactionId, userId);
        }
        if (!flag) {
            // 是否购买了套餐
//            List<UserSet> parentSets = userSetRepo.findAllByUserId(parent);
//            if (CollUtil.isNotEmpty(parentSets)) {
            if (parentUser.isVip()) {
                flag = true;
            }
        }
        if (!flag) {
            return;
        }

        BigDecimal personalAmount = sysConfigService.getBigDecimal("PERSONAL_AMOUNT");
        parentUser.setAmount(parentUser.getAmount().add(personalAmount));
        userRepo.save(parentUser);

        // 个人佣金流水
        commissionRecordRepo.save(CommissionRecord.builder()
                .userId(parent)
                .amount(personalAmount)
                .payMethod(PayMethod.YUE)
                .fromUserId(userId)
                .transactionType(TransactionType.PROMOTE)
                .transactionId(transactionId)
                .build());
    }

    /*
    公司分销
     */
    public void companyDis(Long companyId, String transactionId, Long userId) {
        Company company = companyRepo.findById(companyId).orElseThrow(new BusinessException("无企业"));
        // 用户余额
        User user = userRepo.findById(company.getUserId()).orElseThrow(new BusinessException("无用户"));
        BigDecimal companyAmount = sysConfigService.getBigDecimal("COMPANY_AMOUNT");
        user.setAmount(user.getAmount().add(companyAmount));
        userRepo.save(user);
        // 公司余额
        company.setAmount(company.getAmount().add(companyAmount));
        companyRepo.save(company);

        // 佣金流水
        commissionRecordRepo.save(CommissionRecord.builder()
                .userId(company.getUserId())
                .amount(companyAmount)
                .payMethod(PayMethod.YUE)
                .fromUserId(userId)
                .transactionType(TransactionType.EMPLOYEES_PROMOTE)
                .transactionId(transactionId)
                .build());

    }

    /*
    用户订单
     */
    public Page<OrderInfoVO> my(Pageable pageable, Long userId, List<OrderInfoStatus> status) {
        Map<Long, Package> packageMap = packageRepo.findAll()
                .stream()
                .collect(Collectors.toMap(Package::getId, aPackage -> aPackage));
        return orderInfoRepo.findAll(((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> and = new ArrayList<>();
            and.add(criteriaBuilder.equal(root.get("userId"), userId));
            if (CollUtil.isNotEmpty(status)) {
                List<Predicate> or = new ArrayList<>();
                status.forEach(orderInfoStatus ->
                        or.add(criteriaBuilder.equal(root.get("status"), orderInfoStatus))
                );
                and.add(criteriaBuilder.or(or.toArray(new Predicate[0])));
            }
            criteriaQuery.orderBy(criteriaBuilder.desc(root.get("createdAt")));
            return criteriaBuilder.and(and.toArray(new Predicate[0]));
        }), pageable).map(orderInfo -> {
            OrderInfoVO vo = new OrderInfoVO();
            BeanUtil.copyProperties(orderInfo, vo);
            vo.setAPackage(packageMap.get(orderInfo.getPackageId()));
            List<PackageGoodsDTO> packageGoodsDTOS = packageGoodsRepo.packageGoods(orderInfo.getPackageId());
            vo.setGoods(packageGoodsDTOS);
            return vo;
        });
    }

    public List<OrderInfoVO> toVO(List<OrderInfo> orderInfos) {
        List<OrderInfoVO> orderInfoVOS = new ArrayList<>();
        Set<Long> packageIds = orderInfos.stream().map(OrderInfo::getPackageId).collect(Collectors.toSet());
        Map<Long, Package> packageMap = packageRepo.findAllById(packageIds)
                .stream()
                .collect(Collectors.toMap(Package::getId, apackage -> apackage));
//        Map<Long, String> goodsMap = goodsInfoRepo.findAll()
//                .stream()
//                .collect(Collectors.toMap(GoodsInfo::getId, GoodsInfo::getName));

        orderInfos.forEach(orderInfo -> {
            OrderInfoVO vo = new OrderInfoVO();
            BeanUtil.copyProperties(orderInfo, vo);
            vo.setAPackage(packageMap.get(orderInfo.getPackageId()));
//            List<PackageGoods> packageGoods = packageGoodsRepo.findAllByPackageId(orderInfo.getPackageId());
            List<PackageGoodsDTO> packageGoodsDTOS = packageGoodsRepo.packageGoods(orderInfo.getPackageId());
            vo.setGoods(packageGoodsDTOS);
            orderInfoVOS.add(vo);
        });
        return orderInfoVOS;
    }
}
