package com.izouma.jiashanxia.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.izouma.jiashanxia.domain.CommissionRecord;
import com.izouma.jiashanxia.domain.User;
import com.izouma.jiashanxia.domain.Withdraw;
import com.izouma.jiashanxia.dto.CommissionRecordDTO;
import com.izouma.jiashanxia.dto.PageQuery;
import com.izouma.jiashanxia.enums.AuthorityName;
import com.izouma.jiashanxia.enums.PayMethod;
import com.izouma.jiashanxia.enums.TransactionType;
import com.izouma.jiashanxia.repo.CommissionRecordRepo;
import com.izouma.jiashanxia.repo.UserRepo;
import com.izouma.jiashanxia.repo.WithdrawRepo;
import com.izouma.jiashanxia.security.Authority;
import com.izouma.jiashanxia.utils.JpaUtils;
import lombok.AllArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.Predicate;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Service
@AllArgsConstructor
public class CommissionRecordService {

    private final CommissionRecordRepo commissionRecordRepo;
    private final WithdrawService      withdrawService;
    private final UserRepo             userRepo;
    private final WithdrawRepo         withdrawRepo;

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

    /*
    后台列表
     */
    public Page<CommissionRecord> backAll(PageQuery pageQuery, User user) {
        pageQuery.setSort("createdAt,desc");
        Set<Authority> authorities = user.getAuthorities();
        Map<String, Object> query = pageQuery.getQuery();
        Object company = query.get("companyId");
        query.remove("companyId");

//        if (!authorities.contains(Authority.get(AuthorityName.ROLE_ADMIN)) && authorities.contains(Authority.get(AuthorityName.ROLE_CREATOR))) {
//            Map<String, Object> query = pageQuery.getQuery();
//            query.put("userId", user.getId());
//        }
        //return commissionRecordRepo.findAll(JpaUtils.toSpecification(pageQuery, CommissionRecord.class), JpaUtils.toPageRequest(pageQuery));

        return commissionRecordRepo.findAll(((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> and = JpaUtils.toPredicates(pageQuery, CommissionRecord.class, root, criteriaQuery, criteriaBuilder);
            if (StrUtil.isNotEmpty(pageQuery.getSearch())) {
                withdrawService.getNickname(pageQuery.getSearch(), and, root, criteriaBuilder);
            }
            if (!authorities.contains(Authority.get(AuthorityName.ROLE_ADMIN))) {
                List<Long> userIds = userRepo.findAllByCompanyIdAndDelFalse(user.getCompanyId())
                        .stream()
                        .map(User::getId)
                        .collect(Collectors.toList());
                and.add(root.get("userId").in(userIds));
            } else {
                if (ObjectUtil.isNotEmpty(company)) {
                    List<Long> userIds = userRepo.findAllByCompanyIdAndDelFalse(Long.parseLong(String.valueOf(company)))
                            .stream()
                            .map(User::getId)
                            .collect(Collectors.toList());
                    and.add(root.get("userId").in(userIds));
                }
            }
            return criteriaBuilder.and(and.toArray(new Predicate[0]));
        }), JpaUtils.toPageRequest(pageQuery));

    }

    public Page<CommissionRecord> backAll2(PageQuery pageQuery) {
        pageQuery.setSort("createdAt,desc");
        return commissionRecordRepo.findAll(((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> and = JpaUtils.toPredicates(pageQuery, CommissionRecord.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 List<CommissionRecordDTO> my(Long userId) {
        List<CommissionRecordDTO> my = new ArrayList<>();
        List<CommissionRecord> recordList = commissionRecordRepo.findAllByUserIdAndTransactionTypeNot(userId, TransactionType.WITHDRAW);
        Set<Long> fromUserId = recordList.stream().map(CommissionRecord::getFromUserId).collect(Collectors.toSet());
        Map<Long, User> userMap = userRepo.findAllById(fromUserId)
                .stream()
                .collect(Collectors.toMap(User::getId, user -> user));
        recordList.forEach(record -> {
            CommissionRecordDTO dto = new CommissionRecordDTO();
            BeanUtil.copyProperties(record, dto);
            User fromUser = userMap.get(record.getFromUserId());
            if (ObjectUtil.isNotEmpty(fromUser)) {
                dto.setRemark(fromUser.getNickname());
            }
            my.add(dto);
        });

        List<Withdraw> withdraws = withdrawRepo.findAllByUserId(userId);
        withdraws.forEach(withdraw ->
                my.add(CommissionRecordDTO.builder()
                        .id(withdraw.getId())
                        .userId(userId)
                        .amount(withdraw.getAmount().negate())
                        .createdAt(withdraw.getCreatedAt())
                        .remark("提现账号:" + withdraw.getAccount())
                        .transactionType(TransactionType.WITHDRAW)
                        .withdrawStatus(withdraw.getStatus())
                        .build()
                ));
        my.sort((a, b) -> b.getCreatedAt().compareTo(a.getCreatedAt()));
        return my;

    }

    // 退款佣金流水
    public void refund(String orderId) {
        List<CommissionRecord> records = commissionRecordRepo.findAllByTransactionId(orderId);
        // 相关用户
        Set<Long> ids = records.stream().map(CommissionRecord::getUserId).collect(Collectors.toSet());
        Map<Long, User> userMap = userRepo.findAllById(ids)
                .stream()
                .collect(Collectors.toMap(User::getId, user -> user));

        records.forEach(record -> {
            User user = userMap.get(record.getUserId());
            if (ObjectUtil.isNotEmpty(user)) {
                user.setCacheAmount(user.getCacheAmount().subtract(record.getAmount()));
                // 保存佣金流水
                CommissionRecord build = CommissionRecord.builder()
                        .amount(record.getAmount().negate())
                        .payMethod(PayMethod.YUE)
                        .fromUserId(record.getFromUserId())
                        .transactionId("R" + orderId)
                        .remark(record.getRemark())
                        .transactionType(TransactionType.REFUND)
                        .userId(record.getUserId())
                        .fromUserId(record.getFromUserId())
                        .build();
                commissionRecordRepo.save(build);
            }
        });
        userRepo.saveAll(userMap.values());
    }

    /*
    变为可提现金额
     */
    public void canWithdraw(Long orderId) {
        List<CommissionRecord> records = commissionRecordRepo.findAllByTransactionId(orderId.toString());
        Set<Long> ids = records.stream().map(CommissionRecord::getUserId).collect(Collectors.toSet());
        Map<Long, User> userMap = userRepo.findAllById(ids)
                .stream()
                .collect(Collectors.toMap(User::getId, user -> user));
        records.forEach(record -> {
            User user = userMap.get(record.getUserId());
            BigDecimal amount = record.getAmount();
            if (ObjectUtil.isNotEmpty(user)) {
                user.setCacheAmount(user.getCacheAmount().subtract(amount));
                user.setAmount(amount.add(user.getAmount()));
                userRepo.save(user);
//                switch (record.getTransactionType()) {
//                    case PROMOTE:
//                        user.setPromote(user.getPromote().add(amount));
//                        userRepo.save(user);
//                        break;
//                    case GENERAL:
//                        user.setGeneral(user.getGeneral().add(amount));
//                        userRepo.save(user);
//                        break;
//                    case MAKER:
//                        user.setMaker(user.getMaker().add(amount));
//                        userRepo.save(user);
//                        break;
//                    default:
//                        break;
//                }
            }
        });
    }
}
