package com.fdkankan.platform.order.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fdkankan.common.constant.*;
import com.fdkankan.common.exception.BusinessException;
import com.fdkankan.common.user.SSOUser;
import com.fdkankan.platform.order.entity.*;
import com.fdkankan.platform.order.mapper.IInvoiceMapper;
import com.fdkankan.platform.order.request.RequestPlaceOrder;
import com.fdkankan.platform.order.service.*;
import com.fdkankan.platform.user.request.RequestInvoice;
import com.fdkankan.platform.user.request.RequestTrade;
import com.fdkankan.platform.user.service.IUserService;
import com.fdkankan.platform.user.vo.ResponseInvoice;
import com.fdkankan.platform.user.vo.ResponseOrder;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 发票表 服务实现类
 * </p>
 *
 * @author 
 * @since 2021-12-24
 */
@Service
public class InvoiceServiceImpl extends ServiceImpl<IInvoiceMapper, Invoice> implements IInvoiceService {

    @Autowired
    private IVirtualOrderService virtualOrderService;
    @Autowired
    private IExpansionOrderService expansionOrderService;
    @Autowired
    private IUserService userService;
    @Autowired
    private IOrderService orderService;
    @Autowired
    private IIncrementOrderService incrementOrderService;
    @Resource
    private IInvoiceMapper invoiceMapper;

    @Override
    public Integer getMaxInvoice(RequestInvoice param, String token) {
        Integer maxInvoice = getMaxInvoice(param.getCameraId());
        maxInvoice = maxInvoice < 0 ? 0 : maxInvoice;
        return maxInvoice;
    }

    private Integer getMaxInvoice(Long cameraId){
        QueryWrapper<VirtualOrder> virtualOrderQueryWrapper = new QueryWrapper<>();
        virtualOrderQueryWrapper.lambda().eq(VirtualOrder::getTbStatus,TbStatus.VALID.code());
        virtualOrderQueryWrapper.lambda().eq(VirtualOrder::getCameraId,cameraId);
        List<VirtualOrder> virtualOrders = virtualOrderService.list(virtualOrderQueryWrapper);
        Integer maxInvoice = 0;

        for (VirtualOrder virtualOrder : virtualOrders) {
            if (virtualOrder.getStatus() == 1 && virtualOrder.getPayStatus() == 1){
                maxInvoice += virtualOrder.getPoints();
            }else if (virtualOrder.getStatus() == -2){
                maxInvoice -= virtualOrder.getPoints();
            }
        }

        QueryWrapper<ExpansionOrder> expansionOrderQueryWrapper = new QueryWrapper<>();
        expansionOrderQueryWrapper.lambda().eq(ExpansionOrder::getTbStatus,TbStatus.VALID.code());
        expansionOrderQueryWrapper.lambda().eq(ExpansionOrder::getCameraId,cameraId);
        List<ExpansionOrder> expansionOrders = expansionOrderService.list(expansionOrderQueryWrapper);
        for (ExpansionOrder expansionOrder : expansionOrders) {
            if(expansionOrder.getPayStatus() == 1){
                maxInvoice += expansionOrder.getAmount().intValue();
            }else if (expansionOrder.getPayStatus() == -2){
                maxInvoice -= expansionOrder.getAmount().intValue();
            }
        }

        QueryWrapper<Invoice> invoiceQueryWrapper = new QueryWrapper<>();
        invoiceQueryWrapper.lambda().eq(Invoice::getTbStatus,TbStatus.VALID.code());
        invoiceQueryWrapper.lambda().eq(Invoice::getCameraId,cameraId);
        invoiceQueryWrapper.lambda().eq(Invoice::getConsumeType,1);
        List<Invoice> invoices = this.list(invoiceQueryWrapper);
        for (Invoice invoice : invoices) {
            if (invoice.getMoney() != null){
                maxInvoice -= invoice.getMoney().intValue();
            }
        }
        return maxInvoice;
    }

    @Override
    public Page<ResponseInvoice> listInvoice(RequestInvoice param, String token) {
        QueryWrapper<Invoice> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Invoice::getTbStatus,TbStatus.VALID.code());
        if(token!=null){
            SSOUser ssoUser = userService.getSSOUserByToken(token);
            queryWrapper.lambda().eq(Invoice::getUserId,ssoUser.getId());
        }
        Page<Invoice> page = new Page<>(param.getPageNum(),param.getPageSize());
        queryWrapper.lambda().ne(Invoice::getConsumeType ,-1);
        if(param.getCameraId()!=null){
            queryWrapper.lambda().eq(Invoice::getCameraId ,param.getCameraId());
        }
        if(param.getType()!=null){
            if(param.getType() == 0){
                queryWrapper.lambda().eq(Invoice::getType ,param.getType());
            }else {
                queryWrapper.lambda().ne(Invoice::getType ,0);
            }
        }
        queryWrapper.lambda().orderByDesc(Invoice::getCreateTime);
        Page<Invoice> pageEntity = this.page(page, queryWrapper);

        List<ResponseInvoice> voList = this.convert(pageEntity.getRecords());
        Page<ResponseInvoice> pageVo = new Page<>(param.getPageNum(),param.getPageSize());
        pageVo.setTotal(page.getTotal());
        pageVo.setRecords(voList);

        return pageVo;
    }

    @Override
    public ResponseInvoice mineInvoice(RequestInvoice param, String token) {
        SSOUser ssoUser = userService.getSSOUserByToken(token);
        Invoice mineInvoice = getMineInvoice(ssoUser.getId(), param.getInvoiceType());
        ResponseInvoice responseInvoice = new ResponseInvoice();
        BeanUtils.copyProperties(mineInvoice,responseInvoice);
        return responseInvoice;
    }
    private Invoice getMineInvoice(Long userId,String invoiceType){
        QueryWrapper<Invoice> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Invoice::getTbStatus,TbStatus.VALID.code());
        queryWrapper.lambda().eq(Invoice::getUserId,userId);
        queryWrapper.lambda().eq(Invoice::getConsumeType ,-1);
        queryWrapper.lambda().eq(Invoice::getType ,invoiceType);
        queryWrapper.lambda().last("LIMIT 1");
        List<Invoice> list = this.list(queryWrapper);
        if(list == null || list.size()<=0){
            return null;
        }
        return list.get(0);
    }

    @Override
    public String saveInvoice(RequestInvoice param, String token) {
        SSOUser ssoUser = userService.getSSOUserByToken(token);
        Invoice dbEntity = getMineInvoice(ssoUser.getId(), param.getInvoiceType());
        if (dbEntity == null){
            dbEntity = new Invoice();
        }
        if (param.getCameraId() != null){
            dbEntity.setCameraId(param.getCameraId());
        }
        dbEntity.setType(Integer.valueOf(param.getInvoiceType()));
        dbEntity.setUserId(ssoUser.getId());
        dbEntity.setBankAccount(param.getBankAccount());
        dbEntity.setBankName(param.getBankName());
        dbEntity.setRegisterPhone(param.getRegisterPhone());
        dbEntity.setOrganizedAddress(param.getOrganizedAddress());
        dbEntity.setCode(param.getCode());
        dbEntity.setTitle(param.getTitle());
        dbEntity.setEmailAddress(param.getEmailAddress());
        dbEntity.setConsumeType(-1);
        if(!this.saveOrUpdate(dbEntity)){
            throw new BusinessException(ErrorCode.ERROR_MSG);
        }
        return ServerCode.SUCCESS.message();
    }

    @Override
    public ResponseInvoice detailInvoice(RequestInvoice param, String token) {
        Invoice invoice = this.getById(param.getInvoiceId());
        ResponseInvoice responseInvoice = new ResponseInvoice();
        if(invoice == null){
            return responseInvoice;
        }
        BeanUtils.copyProperties(invoice, responseInvoice);
        return responseInvoice;
    }

    @Override
    public String addInvoice(RequestInvoice param, String token) {
        SSOUser ssoUser = userService.getSSOUserByToken(token);
        if(param.getAmount() == null){
            throw new BusinessException(ErrorCode.MISSING_REQUIRED_PARAMETERS);
        }
        int maxInvoice = this.getMaxInvoice(param.getCameraId());

        if(Integer.parseInt(param.getAmount()) > maxInvoice){
            throw new BusinessException(ErrorCode.FAILURE_CODE_8003);
        }
        return saveOrUpdateInvoice(ssoUser.getId(),param,null);
    }
    private String saveOrUpdateInvoice(Long userId,RequestInvoice param,Invoice invoiceEntity){
        if(invoiceEntity == null){
             invoiceEntity = new Invoice();
            invoiceEntity.setUserId(userId);
            invoiceEntity.setOrderId(param.getOrderId());
        }
        invoiceEntity.setType(Integer.valueOf(param.getInvoiceType()));
        invoiceEntity.setTitle(param.getTitle());
        invoiceEntity.setCode(param.getCode());

        if (3 == invoiceEntity.getType()){
            invoiceEntity.setOrganizedAddress(param.getOrganizedAddress());
            invoiceEntity.setRegisterPhone(param.getRegisterPhone());
            invoiceEntity.setBankName(param.getBankName());
            invoiceEntity.setBankAccount(param.getBankAccount());
        }

        invoiceEntity.setCameraId(param.getCameraId());
        invoiceEntity.setMoney(new BigDecimal(param.getAmount()));
        invoiceEntity.setConsumeType(param.getConsumeType() == null? 1 : param.getConsumeType());

        invoiceEntity.setShipName(param.getShipName());
        invoiceEntity.setShipMobile(param.getShipMobile());
        invoiceEntity.setShipAddress(param.getShipAddress());
        invoiceEntity.setShipAreaPath(param.getShipAreaPath());
        invoiceEntity.setCameraId(param.getCameraId());
        invoiceEntity.setEmailAddress(param.getEmailAddress());
        if(!this.saveOrUpdate(invoiceEntity)){
            throw new BusinessException(ErrorCode.ERROR_MSG);
        }
        return ServerCode.SUCCESS.message();
    }

    @Override
    public String updateInvoice(RequestInvoice param, String token) {
        SSOUser ssoUser = userService.getSSOUserByToken(token);

        if(param.getInvoiceId() != null){
            Invoice invoiceEntity = this.getById(param.getInvoiceId());
            if(invoiceEntity == null){
                throw new BusinessException(ErrorCode.NOT_RECORD);
            }
            return this.saveOrUpdateInvoice(ssoUser.getId(), param,invoiceEntity);
        }
        ResponseOrder order = orderService.getOrderDetail(param.getOrderId());
        if(order == null || order.getTotalAmount() == null){
            throw new BusinessException(ErrorCode.ERROR_MSG);
        }
        param.setAmount(order.getTotalAmount().toString());
        return  this.saveOrUpdateInvoice(ssoUser.getId(),param,null);
    }


    @Override
    public String deleteInvoice(RequestInvoice param, String token) {
        if(param == null || param.getInvoiceId() == null){
            throw new BusinessException(ErrorCode.MISSING_REQUIRED_PARAMETERS);
        }
        if(!this.removeById(param.getInvoiceId())){
            throw new BusinessException(ErrorCode.ERROR_MSG);
        }
        return ServerCode.SUCCESS.message();
    }

    @Override
    public ResponseInvoice openInvoice(RequestInvoice param, String token) {
        SSOUser ssoUser = userService.getSSOUserByToken(token);

        //验证是否已经开票
        this.checkInvoice(param.getOrderId(),param.getConsumeType());
        //获取开票金额
        BigDecimal money = this.getMoney(param.getOrderId(),param.getConsumeType());

        Invoice dbEntity = new Invoice();
        BeanUtils.copyProperties(param, dbEntity);

        dbEntity.setOrderId(null);
        switch (param.getConsumeType()){
            case 0: dbEntity.setOrderId(param.getOrderId());break;
            case 1: dbEntity.setVirtualOrderId(param.getOrderId());break;
            case 2: dbEntity.setIncrementOrderId(param.getOrderId());break;
            case 3: dbEntity.setDownloadOrderId(param.getOrderId());break;
        }

        if (param.getCameraId() != null){
            dbEntity.setCameraId(param.getCameraId());
        }
//        dbEntity.setType(Integer.valueOf(param.get));
        dbEntity.setUserId(ssoUser.getId());
        dbEntity.setMoney(money);
        this.save(dbEntity);

        ResponseInvoice responseInvoice = new ResponseInvoice();
        BeanUtils.copyProperties(dbEntity,responseInvoice);
        return responseInvoice;
    }

    private BigDecimal getMoney(Long orderId, Integer consumeType) {
        BigDecimal money = null;
        switch (consumeType){
            case 1 :
                VirtualOrder virtualOrder = virtualOrderService.getById(orderId);
                if(virtualOrder!=null && virtualOrder.getPayStatus() ==1){
                    money = virtualOrder.getAmount();
                }
                break;
            case 2 :
                IncrementOrder incrementOrder = incrementOrderService.getById(orderId);
                if(incrementOrder!=null && incrementOrder.getPayStatus() ==1){
                    money = incrementOrder.getAmount();
                }
                break;
            default:
                Order order = orderService.getById(orderId);
                if(order!=null && "paid".equals(order.getPaymentStatus())){
                    money = order.getTotalAmount();
                }
                break;
        }
        return money;
    }

    private void checkInvoice(Long orderId, Integer consumeType) {
        QueryWrapper<Invoice> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Invoice::getTbStatus,TbStatus.VALID.code());
        switch (consumeType){
            case 1 :    //验证 消费订单是否开票
                queryWrapper.lambda().eq(Invoice::getVirtualOrderId,orderId);break;
            case 2 :    //验证 权益订单是否开票
                queryWrapper.lambda().eq(Invoice::getIncrementOrderId,orderId);
            case 3 :    //验证 下载订单是否开票
                queryWrapper.lambda().eq(Invoice::getDownloadOrderId,orderId);break;
            default:
                queryWrapper.lambda().eq(Invoice::getOrderId,orderId);break;
        }
        List<Invoice> list = this.list(queryWrapper);
        if(list==null || list.size()<=0){
            throw new BusinessException(AppConstant.FAILURE_CODE_4021,AppConstant.FAILURE_MSG_4021);
        }
    }


    @Override
    public Invoice getByOrderId(Long orderId) {
        QueryWrapper<Invoice> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(Invoice::getTbStatus,TbStatus.VALID.code());
        queryWrapper.lambda().eq(Invoice::getOrderId,orderId);
        queryWrapper.last("LIMIT 1");
        List<Invoice> list = this.list(queryWrapper);
        if(list==null || list.size()<=0){
            return null;
        }
        return list.get(0);
    }

    @Override
    public void saveInvoiceByOrder(Long userId, RequestPlaceOrder order) {
        RequestInvoice param = order.getInvoice();
        Invoice invoiceEntity = new Invoice();
        invoiceEntity.setUserId(userId);
        invoiceEntity.setType(Integer.valueOf(param.getInvoiceType()));
        invoiceEntity.setTitle(param.getTitle());
        invoiceEntity.setCode(param.getCode());
        invoiceEntity.setEmailAddress(param.getEmailAddress());
        if (3 == invoiceEntity.getType()){
            invoiceEntity.setOrganizedAddress(param.getOrganizedAddress());
            invoiceEntity.setRegisterPhone(param.getRegisterPhone());
            invoiceEntity.setBankName(param.getBankName());
            invoiceEntity.setBankAccount(param.getBankAccount());
        }
        invoiceEntity.setConsumeType(0);
        invoiceEntity.setOrderId(order.getOrderId());
        invoiceEntity.setShipName(order.getReceiver().getShipName());
        invoiceEntity.setShipMobile(order.getReceiver().getShipMobile());
        invoiceEntity.setShipAddress(order.getReceiver().getShipAddress());
        invoiceEntity.setShipAreaPath(order.getReceiver().getShipAreaPath());
        invoiceEntity.setEmailAddress(param.getEmailAddress());

        invoiceEntity.setMoney(new BigDecimal(param.getAmount()));
        if(!this.save(invoiceEntity)){
            throw new BusinessException(ErrorCode.ERROR_MSG);
        }
    }

    @Override
    public List<Invoice> getListByParam(RequestTrade trade) {
        trade.setOrderBy("create_time desc");
        return invoiceMapper.getListByParam(null,trade);
    }

    @Override
    public Page<ResponseInvoice> getPageByParam(RequestTrade param) {
        Page<ResponseInvoice> pageVo = new Page<>(param.getPageNum(), param.getPageSize());
        param.setOrderBy("create_time desc");
        List<Invoice> list = invoiceMapper.getListByParam(pageVo,param);
        List<ResponseInvoice> result = this.convert(list);
        pageVo.setRecords(result);
        return pageVo;
    }

    @Override
    public Page<ResponseInvoice> findInvoiceList(RequestTrade param) {
        LambdaQueryWrapper<Invoice> queryWrapper = getWrapperByParam(param);
        Page<Invoice> page = new Page<>(param.getPageNum(),param.getPageSize());
        Page<Invoice> pageEntity = this.page(page, queryWrapper);

        List<ResponseInvoice> result = this.convert(pageEntity.getRecords());

        Page<ResponseInvoice> pageVo = new Page<>(param.getPageNum(),param.getPageSize());
        pageVo.setTotal(pageEntity.getTotal());
        pageVo.setRecords(result);
        return pageVo;
    }

    @Override
    public List<ResponseInvoice> getVoListByParam(RequestTrade param) {
        List<Invoice> list = this.list(getWrapperByParam(param));
        return this.convert(list);
    }

    public LambdaQueryWrapper<Invoice> getWrapperByParam(RequestTrade param){
        LambdaQueryWrapper<Invoice> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Invoice::getTbStatus,TbStatus.VALID.code());
        if(param.getFinish()!=null){
            queryWrapper.eq(Invoice::getFinish,param.getFinish());
        }
        if(param.getOrderId()!=null){
            queryWrapper.eq(Invoice::getOrderId,param.getOrderId());
        }else if(param.getIncrementId()!=null){
            queryWrapper.eq(Invoice::getIncrementOrderId,param.getIncrementId());
        }else if (param.getDownloadId()!=null){
            queryWrapper.eq(Invoice::getDownloadOrderId,param.getDownloadId());
        }
        if(StringUtils.isNotEmpty(param.getSearchKey())){
            queryWrapper.like(Invoice::getTitle,param.getSearchKey())
                    .or().like(Invoice::getEmailAddress,param.getSearchKey())
                    .or().like(Invoice::getShipMobile,param.getSearchKey())
                    .or().like(Invoice::getRegisterPhone,param.getSearchKey());
        }
        if(param.getType()!=null){
            queryWrapper.eq(Invoice::getType,param.getPageNum());
        }
        if(param.getConsumeType() != null){
            queryWrapper.eq(Invoice::getConsumeType,param.getConsumeType());
        }
        queryWrapper.orderByDesc(Invoice::getCreateTime);
        return queryWrapper;
    }

    public List<ResponseInvoice> convert(List<Invoice> list){
        return list.stream().map(invoice -> {
            ResponseInvoice responseInvoice = new ResponseInvoice();
            BeanUtils.copyProperties(invoice, responseInvoice);
            return responseInvoice;
        }).collect(Collectors.toList());
    }

    public String sendExpress(RequestInvoice param) {
        Invoice invoiceEntity = this.getById(param.getInvoiceId());
        if(invoiceEntity == null){
            throw new BusinessException(-1,"开票信息不存在");
        }
        invoiceEntity.setSend(1);
        invoiceEntity.setExpressCompany(param.getExpressCompany());
        invoiceEntity.setExpressNumber(param.getExpressNumber());
        invoiceEntity.setRemarks(param.getRemarks());
        invoiceEntity.setFinish(1);
        invoiceEntity.setSend(1);
        this.updateById(invoiceEntity);
        return ServerCode.SUCCESS.message();
    }
    @Override
    public Invoice sendEInvoice(Long invoiceId, String remarks, String filePath) {
        Invoice invoiceEntity = this.getById(invoiceId);
        if(invoiceEntity == null){
            throw new BusinessException(-1,"开票信息不存在");
        }

        invoiceEntity.setRemarks(remarks);
        invoiceEntity.setEInvoice(filePath);
        invoiceEntity.setFinish(1);
        invoiceEntity.setSend(2);
        this.updateById(invoiceEntity);
        return invoiceEntity;
    }

    @Override
    public Invoice getInvoiceByDownloadOrderId(Long downloadOrderId) {
        LambdaQueryWrapper<Invoice> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Invoice::getDownloadOrderId,downloadOrderId)
                .eq(Invoice::getTbStatus,TbStatus.VALID.code());
        queryWrapper.last("LIMIT 1");
        List<Invoice> list = this.list(queryWrapper);
        if(list == null || list.size() <=0 ){
            return  null;
        }
        return list.get(0);
    }
}
