package org.springblade.common.aop;

import cn.hutool.core.util.ClassUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springblade.common.aop.bean.TenantWrapper;
import org.springblade.common.aop.core.TenantAop;
import org.springblade.common.constant.Agent;
import org.springblade.common.constant.Salesman;
import org.springblade.common.enums.AppConstant;
import org.springblade.common.enums.OrderType;
import org.springblade.common.enums.WithdrawType;
import org.springblade.core.secure.BladeUser;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tenant.BladeTenantHolder;
import org.springblade.core.tool.api.R;
import org.springblade.ldt.agent.entity.AgentBills;
import org.springblade.ldt.agent.entity.AgentRecord;
import org.springblade.ldt.bills.entity.BalanceBills;
import org.springblade.ldt.bills.entity.Bills;
import org.springblade.ldt.bills.entity.PointBills;
import org.springblade.ldt.bills.entity.WithdrawRec;
import org.springblade.ldt.shop.entity.Shop;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.List;

/**
 * @Author: Silent
 * @Description
 * @Date: Created in 16:47 2021/10/13
 * @Modified By:
 */
@Component
@Aspect
@Slf4j
public class TenantIgnoreAop {
	@Autowired
	private TenantWrapper tenantWrapper;

	/**
	 * 环绕方法
	 *
	 * @param pjp
	 * @param tenantAop
	 */
	@Around("@annotation(tenantAop)")
	public Object aroundByAnnotation(ProceedingJoinPoint pjp, TenantAop tenantAop) throws Throwable {
		BladeUser bladeUser = AuthUtil.getUser();
		if (ObjectUtils.isNotEmpty(bladeUser)) {
			//判断是否有业务员注解 && 判断角色是否是业务员
			if (StringUtils.equals(tenantAop.salesman(), Salesman.roleName) && Salesman.isSalesman(bladeUser)) {
				//业务员处理逻辑
				return invokeTenantIgnoreMethodBySalesman(pjp, bladeUser);
			} else if (StringUtils.equals(tenantAop.agent(), Agent.roleName) && Agent.isAgent(bladeUser)) { //判断是否是代理注解 && 判断角色是否是代理
				//代理处理逻辑
				return invokeTenantIgnoreMethodByAgent(pjp, bladeUser);
			}
		}
		return pjp.proceed();
	}

	/**
	 * 拦截业务员Page方法，加上自定义Wrapper
	 *
	 * @param pjp
	 * @return
	 * @throws Throwable
	 */
	@Around("execution(* org.springblade.ldt.bills.service..page(..)) || execution(* org.springblade.ldt.agent.service..page(..))")
	public Object aroundBySalesman(ProceedingJoinPoint pjp) throws Throwable {
		//判断是否加入自定义Wrapper
		if (ObjectUtils.isNotEmpty(tenantWrapper) && tenantWrapper.isJoin()) {
			Object wrapper = null;
			for (Object arg : pjp.getArgs()) {
				if (arg instanceof QueryWrapper) {
					wrapper = arg;
					break;
				}
			}
			//判断是否是账单
			if (ObjectUtils.isNotEmpty(wrapper)) {
				BladeUser bladeUser = AuthUtil.getUser();
				Class<?> superClassGenericType = ReflectionKit.getSuperClassGenericType(pjp.getTarget().getClass(), 1);
				log.info("参数泛型类:{}", superClassGenericType);
				//添加对应SQL
				List<Long> listByShop = Salesman.getSalesmanPromoteIdToListByShop(bladeUser);
				if(listByShop.size()==0){
					listByShop.add(0L);
				}
				List<Long> listByMall = Salesman.getSalesmanPromoteIdToListByMall(bladeUser);
				if(listByMall.size()==0){
					listByMall.add(0L);
				}
				List<Long> listByAgentRecord = Salesman.getSalesmanPromoteIdToListByAgentRecord(bladeUser);
				if(listByAgentRecord.size()==0){
					listByAgentRecord.add(0L);
				}
				if (superClassGenericType == Bills.class) {
					QueryWrapper<Bills> queryWrapper = (QueryWrapper<Bills>) wrapper;
					//添加代理付款流水SQL
					queryWrapper.lambda().and(qw -> {
						//如果是(用户付款/微信支付)->收款方(商家)
						qw.or(wq -> {
							wq.and(wq2->{
								wq2.eq(Bills::getType, OrderType.USER_PAY.name()).or().eq(Bills::getType, OrderType.WECHAT_PAY.name());
							}).in(Bills::getReceiveId, listByShop);
						}).or(wq -> { //如果是(商家充值)->付款方(商家)
							wq.eq(Bills::getType, OrderType.MALL_RECHARGE.name()).in(Bills::getPayId, listByMall);
						}).or(wq -> { //如果是(代理充值)->付款方(代理)
							wq.eq(Bills::getType, OrderType.AGENT_CHARGE.name()).in(Bills::getPayId, listByAgentRecord);
						});
					});
				} else if (superClassGenericType == BalanceBills.class) {
					QueryWrapper<BalanceBills> queryWrapper = (QueryWrapper<BalanceBills>) wrapper;
					queryWrapper.lambda().and(qw -> {
						//如果是(商家赠送积分)->付款方(商家)
						qw.or(wq -> {
							wq.eq(BalanceBills::getType, OrderType.SHOP_SEND.name()).in(BalanceBills::getPayId, listByShop);
						}).or(wq -> { //如果是(商场赠送积分)->付款方(商场)
							wq.eq(BalanceBills::getType, OrderType.MALL_SEND.name()).in(BalanceBills::getPayId, listByMall);
						}).or(wq -> { //如果是(顾客消费)->收款方(商家)
							wq.eq(BalanceBills::getType, OrderType.PAY_CONSUMER.name()).in(BalanceBills::getReceiveId, listByShop);
						});
					});
				} else if (superClassGenericType == AgentBills.class) {
					QueryWrapper<AgentBills> queryWrapper = (QueryWrapper<AgentBills>) wrapper;
					queryWrapper.lambda().and(qw -> {
						//如果是代理账单->代理人
						qw.in(AgentBills::getAgenter, listByAgentRecord);
					});
				} else if (superClassGenericType == PointBills.class) {
					QueryWrapper<PointBills> queryWrapper = (QueryWrapper<PointBills>) wrapper;
					queryWrapper.lambda().and(qw -> {
						//如果是(商家赠送积分)->付款方(商家)
						qw.or(wq -> {
							wq.eq(PointBills::getType, OrderType.SHOP_SEND.name()).in(PointBills::getPayId, listByShop);
						}).or(wq -> { //如果是(商场赠送积分)->付款方(商场)
							wq.eq(PointBills::getType, OrderType.MALL_SEND.name()).in(PointBills::getPayId, listByMall);
						}).or(wq -> { //如果是(顾客消费)->收款方(商家)
							wq.eq(PointBills::getType, OrderType.PAY_CONSUMER.name()).in(PointBills::getReceiveId, listByShop);
						});
					});
				} else if (superClassGenericType == WithdrawRec.class) {
					QueryWrapper<WithdrawRec> queryWrapper = (QueryWrapper<WithdrawRec>) wrapper;
					queryWrapper.lambda().and(qw -> {
						//余额提现->代理、商户
						qw.or(wq -> {
							wq.eq(WithdrawRec::getType, WithdrawType.BALANCE_WITHDRAW.getDec()).and(wq2 -> {
								wq2.and(wq3 -> {
									wq3.eq(WithdrawRec::getOwnerType, AppConstant.USER_TYPE.渠道代理).eq(WithdrawRec::getOwnerId, listByAgentRecord);
								}).or().and(wq3 -> {
									wq3.eq(WithdrawRec::getOwnerType, AppConstant.USER_TYPE.商户).eq(WithdrawRec::getOwnerId, listByShop);
								});
							});
						}).or(wq -> { // 积分提现和应收账单->商家
							wq.and(wq2 -> {
								wq2.eq(WithdrawRec::getType, WithdrawType.POINT_WITHDRAW.getDec()).or().eq(WithdrawRec::getType, WithdrawType.RECEIVABLE_WITHDRAW.getDec());
							}).in(WithdrawRec::getOwnerId, listByShop);
						});
					});
				}
			}
		}
		return pjp.proceed();
	}

	/**
	 * 代理业务员方法(租户忽略)
	 *
	 * @param pjp
	 * @param bladeUser
	 * @return
	 * @throws Throwable
	 */
	public Object invokeTenantIgnoreMethodBySalesman(ProceedingJoinPoint pjp, BladeUser bladeUser) throws Throwable {
		try {
			BladeTenantHolder.setIgnore(Boolean.TRUE);
			//开启自定义Wrapper
			for (Object arg : pjp.getArgs()) {
				if (ObjectUtils.isNotEmpty(arg)) {
					Field salesmanId = ClassUtil.getDeclaredField(arg.getClass(), "salesmanId");
					if (ObjectUtils.isNotEmpty(salesmanId)) {
						salesmanId.setAccessible(true);
						salesmanId.set(arg, bladeUser.getUserId());
					} else if (arg instanceof Bills || arg instanceof BalanceBills //判断是否开启自定义SQL
						|| arg instanceof AgentBills || arg instanceof PointBills
						|| arg instanceof WithdrawRec) {
						tenantWrapper.setJoin(true);
					}
				}
			}
			return pjp.proceed();
		} finally {
			BladeTenantHolder.clear();
		}
	}

	/**
	 * 代理‘代理人’方法(租户忽略)
	 *
	 * @param pjp
	 * @param bladeUser
	 * @return
	 * @throws Throwable
	 */
	public Object invokeTenantIgnoreMethodByAgent(ProceedingJoinPoint pjp, BladeUser bladeUser) throws Throwable {
		try {
			Long agentUserId = Agent.getAgentUserId(bladeUser);
			if (ObjectUtils.isNotEmpty(agentUserId)) {
				BladeTenantHolder.setIgnore(Boolean.TRUE);
				for (Object arg : pjp.getArgs()) {
					if (arg instanceof AgentRecord) {
						((AgentRecord) arg).setAccountId(agentUserId);
					} else if (arg instanceof AgentBills) {
						((AgentBills) arg).setAgenter(agentUserId);
					} else if (arg instanceof Shop) {
						((Shop) arg).setAgenter(agentUserId);
					}
				}
				return pjp.proceed();
			} else {
				return R.fail("该账号未绑定代理,不允许使用");
			}
		} finally {
			BladeTenantHolder.clear();
		}
	}
}
