package com.zbkj.service.service.bcx;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.zbkj.common.constants.OrderConstants;
import com.zbkj.common.exception.CrmebException;
import com.zbkj.common.model.bcx.BcxOrderFapiao;
import com.zbkj.common.model.order.Order;
import com.zbkj.common.model.order.OrderDetail;
import com.zbkj.common.model.user.User;
import com.zbkj.common.page.CommonPage;
import com.zbkj.common.request.PageParamRequest;
import com.zbkj.common.request.bcx.BcxFapiaoTitleRequest;
import com.zbkj.common.request.bcx.BcxOrderFapiaoQueryRequest;
import com.zbkj.common.request.bcx.BcxOrderFapiaoRequest;
import com.zbkj.common.request.bcx.BcxWriteFapiaoRequest;
import com.zbkj.common.response.bcx.BcxOrderFapiaoResponse;
import com.zbkj.common.utils.CrmebUtil;
import com.zbkj.service.dao.bcx.BcxOrderFapiaoDao;
import com.zbkj.service.service.OrderDetailService;
import com.zbkj.service.service.OrderService;
import com.zbkj.service.service.ProductService;
import com.zbkj.service.service.UserService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import javax.validation.Validator;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 订单发票 服务实现类
 */
@Service
public class BcxOrderFapiaoServiceImpl extends ServiceImpl<BcxOrderFapiaoDao, BcxOrderFapiao> implements BcxOrderFapiaoService {

    @Resource
    private BcxOrderFapiaoDao dao;
    @Resource
    private UserService userService;
    @Resource
    private OrderService orderService;
    @Resource
    private OrderDetailService orderDetailService;
    @Resource
    private Validator validator;
    @Resource
    private TransactionTemplate transactionTemplate;
    @Resource
    private ProductService productService;

    @Override
    public BcxOrderFapiaoResponse queryById(Integer id) {
        BcxOrderFapiao fapiao = getFapiaoById(id);
        BcxOrderFapiaoResponse response = new BcxOrderFapiaoResponse();
        BeanUtils.copyProperties(fapiao, response);
        return response;
    }

    public BcxOrderFapiao getFapiaoById(Integer id) {
        Integer userId = userService.getUserIdException();
        BcxOrderFapiao fapiao = dao.selectById(id);
        if (!userId.equals(fapiao.getUid())) {//只能查自己的发票
            throw new CrmebException("找不到发票");
        }
        return fapiao;
    }

    /**
     * 用户查询发票列表
     *
     * @param orderNo
     * @param pageParamRequest
     * @return
     */
    @Override
    public PageInfo<BcxOrderFapiaoResponse> queryPagedList(String orderNo,
                                                           PageParamRequest pageParamRequest) {
        Integer userId = userService.getUserIdException();
        LambdaQueryWrapper<BcxOrderFapiao> lqw = new LambdaQueryWrapper<>();
        lqw.eq(BcxOrderFapiao::getUid, userId);
        //lqw.eq(BcxOrderFapiao::getFapiaoStatus, 1);//已开
        lqw.orderByDesc(BcxOrderFapiao::getId);
        if (StrUtil.isNotBlank(orderNo)) {
            lqw.apply(" FIND_IN_SET ('" + orderNo + "',order_no)");
        }
        Page<BcxOrderFapiao> page = PageHelper.startPage(pageParamRequest.getPage(), pageParamRequest.getLimit());
        List<BcxOrderFapiao> sources = dao.selectList(lqw);
        if (CollUtil.isEmpty(sources)) {
            return CommonPage.copyPageInfo(page, CollUtil.newArrayList());
        }
        List<BcxOrderFapiaoResponse> result = transform2target(sources);
        return CommonPage.copyPageInfo(page, result);
    }

    /**
     * 商户查询发票列表
     *
     * @param request
     * @param pageParamRequest
     * @return
     */
    @Override
    public PageInfo<BcxOrderFapiaoResponse> queryMerchantFapiaoPagedList(Integer merId, BcxOrderFapiaoQueryRequest request,
                                                                         PageParamRequest pageParamRequest) {
        LambdaQueryWrapper<BcxOrderFapiao> lqw = new LambdaQueryWrapper<>();
        lqw.eq(BcxOrderFapiao::getMerId, merId);
        return queryFapiaoList(request, pageParamRequest, lqw);
    }

    /**
     * 平台查询发票列表
     *
     * @param request
     * @param pageParamRequest
     * @return
     */
    @Override
    public PageInfo<BcxOrderFapiaoResponse> queryPlatformFapiaoPagedList(BcxOrderFapiaoQueryRequest request,
                                                                         PageParamRequest pageParamRequest) {
        LambdaQueryWrapper<BcxOrderFapiao> lqw = new LambdaQueryWrapper<>();
        return queryFapiaoList(request, pageParamRequest, lqw);
    }

    private PageInfo<BcxOrderFapiaoResponse> queryFapiaoList(BcxOrderFapiaoQueryRequest request, PageParamRequest pageParamRequest, LambdaQueryWrapper<BcxOrderFapiao> lqw) {
        lqw.orderByDesc(BcxOrderFapiao::getId);
        concatQueryParam(lqw, request);
        Page<BcxOrderFapiao> page = PageHelper.startPage(pageParamRequest.getPage(), pageParamRequest.getLimit());
        List<BcxOrderFapiao> sources = dao.selectList(lqw);
        if (CollUtil.isEmpty(sources)) {
            return CommonPage.copyPageInfo(page, CollUtil.newArrayList());
        }
        List<BcxOrderFapiaoResponse> result = transform2target(sources);
        return CommonPage.copyPageInfo(page, result);
    }

    private void concatQueryParam(LambdaQueryWrapper<BcxOrderFapiao> lqw, BcxOrderFapiaoQueryRequest request) {
        if (request.getFapiaoStatus() != null) {
            lqw.eq(BcxOrderFapiao::getFapiaoStatus, request.getFapiaoStatus());
        }
        if (request.getTimeFrom() != null) {
            lqw.ge(BcxOrderFapiao::getApplyTime, request.getTimeFrom());
        }
        if (request.getTimeTo() != null) {
            lqw.le(BcxOrderFapiao::getApplyTime, request.getTimeTo());
        }
        String keyword = request.getKeyword();
        if (StrUtil.isNotBlank(keyword)) {
            lqw.and(qw ->
                    qw.eq(BcxOrderFapiao::getOrderNo, keyword).or().eq(BcxOrderFapiao::getApplyNo, keyword).or().eq(BcxOrderFapiao::getFapiaoNo, keyword));
        }
        if (CollUtil.isNotEmpty(request.getFapiaoIds())) {
            lqw.in(BcxOrderFapiao::getId, request.getFapiaoIds());
        }
    }

    private List<BcxOrderFapiaoResponse> transform2target(List<BcxOrderFapiao> sources) {
        List<BcxOrderFapiaoResponse> result = new ArrayList<>();
        List<String> orderNoList = sources.stream().map(BcxOrderFapiao::getOrderNo).collect(Collectors.toList());
        List<Integer> uidList = sources.stream().map(BcxOrderFapiao::getUid).collect(Collectors.toList());
        Map<Integer, User> userMap = userService.getUidMapList(uidList);
        for (BcxOrderFapiao source : sources) {
            BcxOrderFapiaoResponse target = new BcxOrderFapiaoResponse();
            BeanUtils.copyProperties(source, target);
            target.setUserName(userMap.get(source.getUid()) == null ? "" : userMap.get(source.getUid()).getNickname());
            result.add(target);
        }
        return result;
    }

    @Override
    public BcxOrderFapiao create(BcxOrderFapiaoRequest request) {
        Integer userId = userService.getUserIdException();
        String orderNo = request.getOrderNo();
        List<String> orderNos = Arrays.asList(orderNo.split(","));
        Map<String, Order> orderMap = orderService.getMapByOrderNoList(orderNos);
        if (orderMap.size() != orderNos.size()) {
            throw new CrmebException("订单不存在" + orderNo);
        }
        Collection<Order> orders = orderMap.values();
        if (orders.stream().map(Order::getMerId).distinct().count() > 1) {
            throw new CrmebException("订单不属于同一个商户，不能合并");
        }
        List<OrderDetail> details = orderDetailService.query().in("order_no", orderNos).list();
        List<Integer> productIds = details.stream().map(OrderDetail::getProductId).collect(Collectors.toList());
        int categoryCount = productService.query().select("category_id").in("id", productIds).groupBy("category_id").list().size();
        if (categoryCount > 1) {
            throw new CrmebException("订单不属于同一个商品分类，不能合并");
        }
        String productInfo = details.stream().map(detail -> detail.getProductName() + ":" + detail.getPrice() + "(元)*" + detail.getPayNum() + "份").collect(Collectors.joining(";"));
        orders.forEach(order -> {
            if (!userId.equals(order.getUid())) {
                throw new CrmebException("非法请求");
            }
            if (order.getStatus() != 6) {
                throw new CrmebException("订单未完成，不能申请" + order.getOrderNo());
            }
            if (order.getFapiaoStatus() != 0) {
                throw new CrmebException("未开发票的订单才能申请" + order.getOrderNo());
            }
            order.setFapiaoStatus(2);
        });
        validateParam(request);
        BcxOrderFapiao fapiao = new BcxOrderFapiao();
        BeanUtils.copyProperties(request, fapiao);
        fapiao.setUid(userId);
        fapiao.setMerId(orders.iterator().next().getMerId());
        fapiao.setApplyTime(new Date());
        fapiao.setFapiaoStatus(0);
        fapiao.setApplyNo(CrmebUtil.getOrderNo(OrderConstants.FAPIAO_APPLY_PREFIX));
        fapiao.setAmount(orders.stream().map(Order::getPayPrice).reduce(BigDecimal.ZERO, BigDecimal::add));
        fapiao.setBizType(orders.iterator().next().getBizType());
        fapiao.setProductInfo(productInfo);
        fapiao.setOrderNo(orderNo);
        if (transactionTemplate.execute(transactionStatus -> {
            orderService.updateBatchById(orders);
            return save(fapiao);
        })) {
            return fapiao;
        }
        return null;
    }

    public void validateParam(BcxOrderFapiaoRequest request) {
        if (request.getTitleType() == 0 && request.getFapiaoType() == 1) {
            throw new CrmebException("个人只能开增值税普通发票");
        }
        if (request.getTitleType() == 1) {//企业
            if (request.getFapiaoType() == 0) {//普通
                validator.validate(request, BcxFapiaoTitleRequest.CompanyPlainGroup.class);
            } else {
                validator.validate(request, BcxFapiaoTitleRequest.CompanyDedicatedGroup.class);
            }
        }
    }

    @Override
    public Boolean update(BcxOrderFapiaoRequest request) {
        BcxOrderFapiao fapiao = getFapiaoById(request.getId());
        if (fapiao.getFapiaoStatus() != 0) {
            throw new CrmebException("发票申请已处理，不能修改");
        }
        if (!fapiao.getOrderNo().equals(request.getOrderNo())) {
            throw new CrmebException("订单号不能修改");
        }
        validateParam(request);
        BeanUtils.copyProperties(request, fapiao);
        return updateById(fapiao);
    }

    @Override
    public Boolean delete(Integer id) {
        BcxOrderFapiao fapiao = getFapiaoById(id);
        if (fapiao.getFapiaoStatus() != 0) {
            throw new CrmebException("发票申请已处理，不能删除");
        }
        return removeById(id);
    }

    @Override
    public BcxOrderFapiao getFapiaoByOrderNo(String orderNo) {
        //Integer userId = userService.getUserIdException();
        LambdaQueryWrapper<BcxOrderFapiao> lqw = new LambdaQueryWrapper<>();
        //lqw.eq(BcxOrderFapiao::getUid, userId);
        //lqw.eq(BcxOrderFapiao::getFapiaoStatus, 1);//已开
        lqw.orderByDesc(BcxOrderFapiao::getId);
        if (StrUtil.isNotBlank(orderNo)) {
            lqw.apply(" FIND_IN_SET ('" + orderNo + "',order_no)");
            return dao.selectOne(lqw);
        }
        return null;
    }

    /**
     * 商户批量开票
     *
     * @param request
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean writeFapiao(BcxWriteFapiaoRequest request, Integer merId) {
        String applyNo = request.getApplyNo();
        LambdaQueryWrapper<BcxOrderFapiao> lqw = new LambdaQueryWrapper<>();
        lqw.eq(BcxOrderFapiao::getApplyNo, applyNo);
        List<BcxOrderFapiao> fapiaoList = dao.selectList(lqw);
        if (fapiaoList.size() < 1) {
            throw new CrmebException("流水号不对，系统找不到相应的记录");
        }
        if (fapiaoList.stream().anyMatch(f -> f.getFapiaoStatus() == 1)) {
            throw new CrmebException("流水号重复或已开完票，请核对");
        }
        if (fapiaoList.stream().anyMatch(f -> !Objects.equals(f.getMerId(), merId))) {
            throw new CrmebException("流水号不属于商户" + merId + "无法开票");
        }
        List<String> orderNoList = fapiaoList.stream().flatMap(f -> Arrays.stream(f.getOrderNo().split(","))).collect(Collectors.toList());
        fapiaoList.forEach(f -> {
            f.setFapiaoNo(request.getFapiaoNo());
            f.setFapiaoStatus(1);
            f.setRemark(request.getRejectReason());
            if (StrUtil.isNotBlank(request.getWriteTime())){
                try {
                    f.setWriteTime(DateUtil.parse(request.getWriteTime()));
                }catch (Exception e){
                    log.error("导入开票日期格式错误",e);
                    f.setWriteTime(new Date());
                }
            }else {
                f.setWriteTime(new Date());
            }
        });
        updateBatchById(fapiaoList);
        orderService.writeFapiaoSuccess(orderNoList);
        return true;
    }
}
