package com.yuchen.saas.park.service.service.property.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yuchen.saas.park.api.dto.property.PropertyFeeItemAddDto;
import com.yuchen.saas.park.api.dto.property.PropertyFeeItemQueryDto;
import com.yuchen.saas.park.api.dto.property.PropertyFeeItemUpdateStatusDto;
import com.yuchen.saas.park.api.entity.property.PropertyFeeItem;
import com.yuchen.saas.park.api.entity.property.PropertyFeeItemDetail;
import com.yuchen.saas.park.api.enums.property.FeeItemTypeEnum;
import com.yuchen.saas.park.api.vo.property.PropertyFeeItemPageVo;
import com.yuchen.saas.park.api.vo.property.PropertyPrepaymentFeeItemInfoVo;
import com.yuchen.saas.park.service.mapper.property.PropertyFeeItemMapper;
import com.yuchen.saas.park.service.service.property.IPropertyFeeItemDetailService;
import com.yuchen.saas.park.service.service.property.IPropertyFeeItemService;
import com.yuchen.saas.park.service.service.property.PropertyFeeStandardService;
import com.yuchen.saas.payment.api.feign.ISaasInvoiceTaxCategoryFeign;
import com.yuchen.saas.payment.api.vo.invoice.SaasInvoiceTaxCategoryVO;
import org.nest.springwrap.core.log.exception.ServiceException;
import org.nest.springwrap.core.mp.base.BaseServiceImpl;
import org.nest.springwrap.core.mp.support.Condition;
import org.nest.springwrap.core.mp.support.NestPage;
import org.nest.springwrap.core.secure.ContextUser;
import org.nest.springwrap.core.secure.utils.AuthUtil;
import org.nest.springwrap.core.tool.api.R;
import org.nest.springwrap.core.tool.utils.Func;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 费用项目 服务实现类
 * </p>
 *
 * @author cxj
 * @since 2023-12-12
 */
@Service
public class PropertyFeeItemServiceImpl extends BaseServiceImpl<PropertyFeeItemMapper, PropertyFeeItem> implements IPropertyFeeItemService {

    @Resource
    private IPropertyFeeItemDetailService iPropertyFeeItemDetailService;

    @Resource
    private ISaasInvoiceTaxCategoryFeign iSaasInvoiceTaxCategoryFeign;

    @Resource
    private PropertyFeeStandardService propertyFeeStandardService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveOrUpdate(PropertyFeeItemAddDto param) {
        LambdaQueryWrapper<PropertyFeeItem> queryWrapper1 = Wrappers.lambdaQuery();
        queryWrapper1.eq(PropertyFeeItem::getFeeItemName,param.getFeeItemName())
                .eq(PropertyFeeItem::getParkId,param.getParkId())
                .ne(Func.isNotEmpty(param.getId()),PropertyFeeItem::getId,param.getId());
        if(count(queryWrapper1)>0){
            throw new ServiceException("已存在相同的费用项目名称!");
        }

        PropertyFeeItem dto= new PropertyFeeItem();
        if(Func.isNotEmpty(param.getId())){
            PropertyFeeItem feeItem = getById(param.getId());
            if(Func.isEmpty(feeItem)){
                throw new ServiceException("所选数据不存在!");
            }
            if (Func.isNotEmpty(feeItem.getEnableStatus())&&feeItem.getEnableStatus()==1){
                throw new ServiceException("已启用的项目不支持编辑!");
            }
            dto.setId(feeItem.getId());
            dto.setFeeItemCode(feeItem.getFeeItemCode());
            LambdaQueryWrapper<PropertyFeeItemDetail> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.eq(PropertyFeeItemDetail::getFeeItemId,param.getId());
            iPropertyFeeItemDetailService.remove(queryWrapper);
        }else{
            dto.setFeeItemCode(Func.random(16));
            ContextUser user = AuthUtil.getUser();
            if(Func.isNotEmpty(user)){
                dto.setCustomerId(user.getCustomerManageId());
            }
        }
        dto.setParkId(param.getParkId());
        dto.setFeeSubject(param.getFeeSubject());
        dto.setFeeItemName(param.getFeeItemName());
        dto.setRemark(param.getRemark());
        switch (FeeItemTypeEnum.matchCode(param.getFeeSubject())){
            case COLLECTION_FEE:
                dto.setTaxCategoryId(param.getTaxCategoryId());
                dto.setIsTaxInclusive(param.getIsTaxInclusive());
                return saveOrUpdate(dto);
            case PREPAID_DEPOSIT:
                if(Func.isEmpty(param.getBalanceType())){
                    throw new ServiceException("请选择用于冲抵的项目");
                }
                dto.setIsSetCondition(param.getIsSetCondition());
                if(Func.isNotEmpty(param.getIsSetCondition())&&param.getIsSetCondition()==1){
                    if(Func.isEmpty(param.getConditionFeeItemId())||Func.isEmpty(param.getConditionType())||
                            Func.isEmpty(param.getConditionNum())||Func.isEmpty(param.getMaxAmount())){
                        throw new ServiceException("请填充完整充值条件");
                    }
                    dto.setConditionFeeItemId(param.getConditionFeeItemId());
                    dto.setConditionType(param.getConditionType());
                    dto.setConditionNum(param.getConditionNum());
                    dto.setMaxAmount(param.getMaxAmount());
                }
                dto.setBalanceType(param.getBalanceType());
                if(Func.isNotEmpty(param.getBalanceType())&&param.getBalanceType()==2){
                    if(Func.isEmpty(param.getItemId())){
                        throw new ServiceException("请选择指定项目");
                    }
                }
                if(saveOrUpdate(dto)&&Func.isNotEmpty(param.getItemId())){
                    for (Long item:param.getItemId()) {
                        PropertyFeeItem feeItem = getById(item);
                        if(Func.isEmpty(feeItem)){
                            throw new ServiceException("所选项目已经不存在");
                        }
                        PropertyFeeItemDetail feeItemDetail=new PropertyFeeItemDetail();
                        feeItemDetail.setFeeItemId(dto.getId());
                        feeItemDetail.setFeeItemBindingId(item);
                        feeItemDetail.setParkId(dto.getParkId());
                        ContextUser user = AuthUtil.getUser();
                        if(Func.isNotEmpty(user)){
                            feeItemDetail.setCustomerId(user.getCustomerManageId());
                        }
                        iPropertyFeeItemDetailService.save(feeItemDetail);
                    }
                }
                break;
            case SECURITY_DEPOSIT:
                return saveOrUpdate(dto);
            case NONBUSINESS_INCOME:
                dto.setTaxCategoryId(param.getTaxCategoryId());
                dto.setIsTaxInclusive(param.getIsTaxInclusive());
                return saveOrUpdate(dto);
            case MAIN_BUSINESS_INCOME:
                dto.setTaxCategoryId(param.getTaxCategoryId());
                dto.setIsTaxInclusive(param.getIsTaxInclusive());
                return saveOrUpdate(dto);
            default:
                break;
        }
        return true;
    }

    @Override
    public NestPage<PropertyFeeItemPageVo> getPage(PropertyFeeItemQueryDto dto) {
        LambdaQueryWrapper<PropertyFeeItem> queryWrapper = Wrappers.lambdaQuery();
        queryWrapper.eq(Func.isNotEmpty(dto.getFeeSubject()),PropertyFeeItem::getFeeSubject,dto.getFeeSubject())
                .in(Func.isNotEmpty(dto.getFeeSubjects()),PropertyFeeItem::getFeeSubject,dto.getFeeSubjects())
                .like(Func.isNotEmpty(dto.getFeeItemName()),PropertyFeeItem::getFeeItemName,dto.getFeeItemName())
                .eq(Func.isNotEmpty(dto.getEnableStatus()),PropertyFeeItem::getEnableStatus,dto.getEnableStatus())
                .eq(PropertyFeeItem::getParkId,dto.getParkId())
                .orderByDesc(PropertyFeeItem::getCreateTime);
        IPage<PropertyFeeItem> page = this.page(Condition.getPage(dto), queryWrapper);
        IPage<PropertyFeeItemPageVo> result=new Page<>();
        Func.copy(page,result);
        List<PropertyFeeItemPageVo> list=new ArrayList<>();
        if(Func.isEmpty(page.getRecords())){
            result.setRecords(list);
            return NestPage.of(result);
        }
        list= page.getRecords().stream().map(a -> buildVo(a)).collect(Collectors.toList());
        result.setRecords(list);
        return NestPage.of(result);
    }

    private PropertyFeeItemPageVo buildVo(PropertyFeeItem a){
        PropertyFeeItemPageVo vo=Func.copy(a,PropertyFeeItemPageVo.class);
        if(Func.isNotEmpty(a.getTaxCategoryId())){
            R<SaasInvoiceTaxCategoryVO> feignResult = iSaasInvoiceTaxCategoryFeign.getTaxCategoryById(a.getTaxCategoryId());
            if(feignResult.isSuccess()&&Func.isNotEmpty(feignResult.getData())){
                vo.setCategoryName(feignResult.getData().getCategoryName());
                vo.setGeneralTaxRate(feignResult.getData().getGeneralTaxRate());
            }
        }
        if(FeeItemTypeEnum.PREPAID_DEPOSIT.getValue().equals(a.getFeeSubject())
                &&Func.isNotEmpty(a.getBalanceType())&&a.getBalanceType()==2){
            LambdaQueryWrapper<PropertyFeeItemDetail> itemQueryWrapper = Wrappers.lambdaQuery();
            itemQueryWrapper.eq(PropertyFeeItemDetail::getFeeItemId,a.getId());
            List<PropertyFeeItemDetail> itemDetailList = iPropertyFeeItemDetailService.list(itemQueryWrapper);
            if(Func.isNotEmpty(itemDetailList)){
                vo.setItem(listByIds(itemDetailList.stream().map(b->b.getFeeItemBindingId()).collect(Collectors.toList())));
            }
        }
        vo.setFeeSubjectName(FeeItemTypeEnum.getDescByCode(a.getFeeSubject()));
        return vo;
    }

    @Override
    public Boolean del(Long id) {
        PropertyFeeItem dto = getById(id);
        if(Func.isEmpty(dto)){
            throw new ServiceException("所选数据已不存在!");
        }
        if(Func.isNotEmpty(dto.getEnableStatus())&&dto.getEnableStatus()==1){
            throw new ServiceException("收费项目已启用,无法进行删除!");
        }
        if(propertyFeeStandardService.countByFeeItemId(id)>0){
            throw new ServiceException("收费项已绑定收费标准,无法进行删除!");
        }
        return deleteLogic(Arrays.asList(id));
    }

    @Override
    public Boolean updateStatus(PropertyFeeItemUpdateStatusDto param) {
        PropertyFeeItem dto = getById(param.getId());
        if(Func.isEmpty(dto)){
            throw new ServiceException("所选数据已不存在!");
        }
        if (Func.isNotEmpty(dto.getEnableStatus())&&dto.getEnableStatus().equals(param.getEnableStatus())){
            return true;
        }else{
            dto.setEnableStatus(param.getEnableStatus());
            return updateById(dto);
        }
    }

    @Override
    public PropertyFeeItemPageVo getDetailById(Long id) {
        PropertyFeeItem dto = getById(id);
        if(Func.isEmpty(dto)){
            throw new ServiceException("所选数据已不存在!");
        }
        return buildVo(dto);
    }

    @Override
    public List<Long> getFeeItemBindFeeIdList(Long feeItemId) {
        LambdaQueryWrapper<PropertyFeeItemDetail> qw = new LambdaQueryWrapper<>();
        qw.eq(PropertyFeeItemDetail::getFeeItemId,feeItemId);
        return iPropertyFeeItemDetailService.list(qw).stream().map(PropertyFeeItemDetail::getFeeItemBindingId).collect(Collectors.toList());
    }

    @Override
    public List<PropertyPrepaymentFeeItemInfoVo> listPrepaymentFeeItemInfo(List<Long> feeItemIdList) {
        if (Func.isEmpty(feeItemIdList)) {
            return new ArrayList<>();
        }
        QueryWrapper<String> qw = new QueryWrapper<>();
        qw.in("fi.id",feeItemIdList);
        qw.eq("fi.fee_subject",FeeItemTypeEnum.PREPAID_DEPOSIT.getValue());
        return this.baseMapper.listPrepaymentFeeItemInfo(qw);
    }
}
