package com.bonus.common.biz.aspect;

import com.alibaba.fastjson2.JSON;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.bonus.common.biz.annotation.StoreLog;
import com.bonus.common.biz.domain.BmStorageLog;
import com.bonus.common.biz.domain.lease.LeaseOutDetails;
import com.bonus.common.biz.domain.lease.LeaseOutRequestVo;
import com.bonus.common.biz.domain.purchase.PurchaseDto;
import com.bonus.common.biz.domain.repair.RepairInputDetails;
import com.bonus.common.biz.enums.InputOutEnum;
import com.bonus.common.biz.enums.MaTypeManageTypeEnum;
import com.bonus.common.biz.service.AsyncStoreLogService;
import com.bonus.common.biz.utils.HttpResult;
import com.bonus.common.core.constant.SecurityConstants;
import com.bonus.common.core.domain.R;
import com.bonus.common.core.utils.ServletUtils;
import com.bonus.common.core.utils.StringUtils;
import com.bonus.common.security.utils.SecurityUtils;
import com.bonus.system.api.RemoteUserService;
import com.bonus.system.api.model.LoginUser;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.ObjectUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;

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

/**
 * @author : 阮世耀
 * @version : 1.0
 * @PackagePath: com.bonus.common.biz.aspect
 * @CreateTime: 2024-12-06  15:04
 * @Description: 物资库存日志记录
 */
@Aspect
@Component
public class StoreLogAspect {

    private static final Logger log = LoggerFactory.getLogger(StoreLogAspect.class);

    /** 排除敏感属性字段 */
    public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" };

    /** Mapper序列化JSON */
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    @Resource
    private AsyncStoreLogService asyncStoreLogService;

    @Resource
    private RemoteUserService remoteUserService;

    /**
     * 处理完请求后执行
     *
     * @param joinPoint 切点
     */
    @AfterReturning(pointcut = "@annotation(storeLog)", returning = "jsonResult")
    public void doAfterReturning(JoinPoint joinPoint, StoreLog storeLog, Object jsonResult)
    {
        System.err.println("进入切面");
        handelStoreLog(joinPoint, storeLog, null, jsonResult);
    }

    protected void handelStoreLog(final JoinPoint joinPoint, StoreLog storeLog, final Exception e, Object jsonResult) {
        List<BmStorageLog> bmStorageLogList = new ArrayList<>();
        try {
            // 处理设置注解上的参数
            setRequestValue(joinPoint, bmStorageLogList);

            for (BmStorageLog bmStorageLog : bmStorageLogList) {
                bmStorageLog.setStatus(200L);
                // 请求的地址
                bmStorageLog.setMethod(StringUtils.substring(Objects.requireNonNull(ServletUtils.getRequest()).getRequestURI(), 0, 255));
                bmStorageLog.setCreator(SecurityUtils.getLoginUser().getSysUser().getNickName());
                if (e != null) {
                    bmStorageLog.setStatus(500L);
                    bmStorageLog.setJsonResult(StringUtils.substring(e.getMessage(), 0, 2000));
                }
                // 设置方法名称
                String className = joinPoint.getTarget().getClass().getName();
                String methodName = joinPoint.getSignature().getName();
                bmStorageLog.setModelTitle(className + "." + methodName + "()");
                // 设置请求方式
                bmStorageLog.setModelTitle(storeLog.title());

                if (StringUtils.isNotNull(jsonResult)) {
                    bmStorageLog.setJsonResult(StringUtils.substring(JSON.toJSONString(jsonResult), 0, 2000));
                    HttpResult msgCode = OBJECT_MAPPER.readValue(bmStorageLog.getJsonResult(), HttpResult.class);
                    bmStorageLog.setResultCode((long) msgCode.getCode());
                    bmStorageLog.setStatus((long) (msgCode.getCode()==200 ? 0 : 1));
                    bmStorageLog.setResultMsg(msgCode.getMsg());
                }
            }

            // 保存数据库
            System.err.println("调用Feign");
            asyncStoreLogService.batchInsert(bmStorageLogList);
        } catch (Exception exp) {
            // 记录本地异常日志
            log.error("异常信息:{}", exp.getMessage());
            exp.printStackTrace();
        }
    }


    /**
     * 获取请求的参数，放到log中
     *
     * @param bmStorageLogList 物资日志
     * @throws Exception 异常
     */
    private void setRequestValue(JoinPoint joinPoint, List<BmStorageLog> bmStorageLogList) throws Exception {
        System.out.println("进入获取请求参数");
        String requestMethod = ServletUtils.getRequest().getMethod();
        Map<?, ?> paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest());

        if (StringUtils.isEmpty(paramsMap) && (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod))) {
            // 领料出库库存变化
            if (joinPoint.getArgs()[0] instanceof LeaseOutRequestVo) {
                LeaseOutRequestVo lod = (LeaseOutRequestVo) joinPoint.getArgs()[0];
                LeaseOutDetails leaseOutDetails = lod.getLeaseOutDetailsList().get(0);
                BmStorageLog bmStorageLog = new BmStorageLog();
                bmStorageLog.setTaskId(leaseOutDetails.getTaskId());
                bmStorageLog.setTypeId(leaseOutDetails.getTypeId());
                bmStorageLog.setTypeName(leaseOutDetails.getTypeModelName());
                bmStorageLog.setManageType(String.valueOf(leaseOutDetails.getManageType()));
                bmStorageLog.setTypeModelName(leaseOutDetails.getTypeName());
                bmStorageLog.setPreStoreNum(leaseOutDetails.getPreStoreNum());
                bmStorageLog.setAgreementId(leaseOutDetails.getAgreementId());
                //数量类型设备
                if (leaseOutDetails.getManageType().equals(MaTypeManageTypeEnum.NUMBER_DEVICE.getTypeId())) {
                    bmStorageLog.setOutNum(leaseOutDetails.getInputNum());
                    bmStorageLog.setPostStoreNum(leaseOutDetails.getPreStoreNum().subtract(bmStorageLog.getOutNum()));
                    bmStorageLog.setOutType(InputOutEnum.NUMBER_DEVICE.getTypeId());
                    bmStorageLogList.add(bmStorageLog);
                } else {
                    //编码、二维码、标准箱类型设备
                    String maCode = lod.getLeaseOutDetailsList().stream()
                            .map(LeaseOutDetails::getMaCode)
                            .filter(Objects::nonNull)
                            .collect(Collectors.joining(","));
                    bmStorageLog.setMaCode(maCode);
                    bmStorageLog.setOutNum(BigDecimal.valueOf(lod.getLeaseOutDetailsList().size()));
                    bmStorageLog.setPostStoreNum(leaseOutDetails.getPreStoreNum().subtract(bmStorageLog.getOutNum()));
                    if (leaseOutDetails.getOutType() != null) {
                        if (leaseOutDetails.getOutType().equals(InputOutEnum.STANDARD_BOX.getTypeId())) {
                            bmStorageLog.setOutType(InputOutEnum.STANDARD_BOX.getTypeId());
                        } else if (leaseOutDetails.getOutType().equals(InputOutEnum.QR_CODE.getTypeId())) {
                            bmStorageLog.setOutType(InputOutEnum.QR_CODE.getTypeId());
                        }
                    } else if (leaseOutDetails.getManageType().equals(MaTypeManageTypeEnum.CODE_DEVICE.getTypeId())) {
                        bmStorageLog.setOutType(InputOutEnum.CODE_DEVICE.getTypeId());
                    }
                    bmStorageLogList.add(bmStorageLog);
                }
            }
            // 新购验收任务
            if (joinPoint.getArgs()[0] instanceof PurchaseDto) {
                PurchaseDto purchaseDto = (PurchaseDto) joinPoint.getArgs()[0];
                BmStorageLog bmStorageLog = new BmStorageLog();
                // 公共部分
                bmStorageLog.setTypeId(Long.valueOf(purchaseDto.getTypeId()));
                bmStorageLog.setTypeName(purchaseDto.getTypeName());
                bmStorageLog.setTypeModelName(purchaseDto.getTypeModelName());
                bmStorageLog.setManageType(String.valueOf(purchaseDto.getManageType()));
                bmStorageLog.setPostStoreNum(purchaseDto.getPostStoreNum());
                bmStorageLog.setPreStoreNum(purchaseDto.getPreStoreNum());
                bmStorageLog.setTaskId(String.valueOf(purchaseDto.getTaskId()));
                // 根据 InPutList 设置 InNum
                if (CollectionUtils.isNotEmpty(purchaseDto.getInPutList())) {
                    bmStorageLog.setInNum(BigDecimal.valueOf(purchaseDto.getInPutList().size()));
                    String maCode = purchaseDto.getInPutList().stream()
                            .filter(Objects::nonNull)
                            .map(PurchaseDto::getMaCode)
                            .collect(Collectors.joining(","));
                    bmStorageLog.setMaCode(maCode);
                    bmStorageLog.setInputType(InputOutEnum.CODE_DEVICE.getTypeId());
                    bmStorageLog.setManageType(String.valueOf(InputOutEnum.CODE_DEVICE.getTypeId()));
                } else {
                    bmStorageLog.setManageType(String.valueOf(InputOutEnum.NUMBER_DEVICE.getTypeId()));
                    bmStorageLog.setInNum(purchaseDto.getInputNum());
                    bmStorageLog.setInputType(InputOutEnum.NUMBER_DEVICE.getTypeId());
                }
                bmStorageLogList.add(bmStorageLog);
            }
            //修饰入库库存变化 /repair_input_details/warehouse
            if (joinPoint.getArgs()[0] instanceof RepairInputDetails) {
                RepairInputDetails repairInputDetails = (RepairInputDetails) joinPoint.getArgs()[0];
                if (repairInputDetails.getTaskId() != null && repairInputDetails.getTypeId() != null && CollectionUtils.isEmpty(repairInputDetails.getOutTaskList())) {
                    // 内层入库
                    BmStorageLog bmStorageLog = new BmStorageLog();
                    bmStorageLog.setTaskId(String.valueOf(repairInputDetails.getTaskId()));
                    bmStorageLog.setTypeId(repairInputDetails.getTypeId());
                    bmStorageLog.setPreStoreNum(repairInputDetails.getPreStoreNum());
                    // 编码类型入库
                    if (CollectionUtils.isNotEmpty(repairInputDetails.getMaCodeList())) {
                        bmStorageLog.setManageType(String.valueOf(InputOutEnum.CODE_DEVICE.getTypeId()));
                        bmStorageLog.setInNum(BigDecimal.valueOf(repairInputDetails.getMaCodeList().size()));
                        String maCode = repairInputDetails.getMaCodeList().stream()
                                .filter(Objects::nonNull)
                                .map(RepairInputDetails::getMaCode)
                                .collect(Collectors.joining(","));
                        bmStorageLog.setMaCode(maCode);
                        bmStorageLog.setInputType(repairInputDetails.getInputType() != null ?
                                    repairInputDetails.getInputType() : InputOutEnum.CODE_DEVICE.getTypeId() );
                    } else {
                        bmStorageLog.setManageType(String.valueOf(InputOutEnum.NUMBER_DEVICE.getTypeId()));
                        bmStorageLog.setInNum(repairInputDetails.getInputNum());
                        bmStorageLog.setInputType(InputOutEnum.NUMBER_DEVICE.getTypeId());
                    }
                    bmStorageLog.setPostStoreNum(repairInputDetails.getPreStoreNum().add(bmStorageLog.getInNum()));
                    bmStorageLogList.add(bmStorageLog);
                    // 外层入库
                } else if (CollectionUtils.isNotEmpty(repairInputDetails.getOutTaskList())) {
                    for (RepairInputDetails inputDetails : repairInputDetails.getDetailsList()) {
                        BmStorageLog bmStorageLog = new BmStorageLog();
                        bmStorageLog.setTaskId(String.valueOf(inputDetails.getTaskId()));
                        bmStorageLog.setTypeId(inputDetails.getTypeId());
                        bmStorageLog.setPreStoreNum(inputDetails.getPreStoreNum());
                        bmStorageLog.setInNum(inputDetails.getPendingInputNum());
                        // 编码类型入库
                        if (inputDetails.getManageType().equals(String.valueOf(InputOutEnum.CODE_DEVICE.getTypeId()))) {
                            bmStorageLog.setManageType(String.valueOf(InputOutEnum.CODE_DEVICE.getTypeId()));
                            bmStorageLog.setMaCode(inputDetails.getMaCode());
                            bmStorageLog.setInputType(InputOutEnum.CODE_DEVICE.getTypeId());
                            // 数量类型入库
                        } else if (inputDetails.getManageType().equals(String.valueOf(InputOutEnum.NUMBER_DEVICE.getTypeId()))) {
                            bmStorageLog.setManageType(String.valueOf(InputOutEnum.NUMBER_DEVICE.getTypeId()));
                            bmStorageLog.setInputType(InputOutEnum.NUMBER_DEVICE.getTypeId());
                        }
                        bmStorageLog.setPostStoreNum(inputDetails.getPreStoreNum().add(bmStorageLog.getInNum()));
                        bmStorageLogList.add(bmStorageLog);
                    }
                }
            }
        }
    }
}
