package jnpf.attendance.annotation;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import jnpf.attendance.mapper.AttendanceGroupMapper;
import jnpf.attendance.mapper.AttendanceMachineLogMapper;
import jnpf.attendance.service.AttendanceUserService;
import jnpf.base.UserInfo;
import jnpf.entity.AttendanceGroupUser;
import jnpf.entity.attendance.AttendanceMachineLog;
import jnpf.enums.attendance.ActionEnum;
import jnpf.enums.attendance.MachineEnum;
import jnpf.model.attendance.vo.GroupInfoVo;
import jnpf.model.attendance.vo.attendance.UserTenantVo;
import jnpf.util.ConstantUtil;
import jnpf.util.DateUtil;
import jnpf.util.FtbUtil;
import jnpf.util.JsonUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.MutablePair;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 考勤机切面
 *
 * @author yanwenfu
 * @create 2024-07-30
 */
@Aspect
@Component
@RefreshScope
public class MachineAspect {

    @Value("${machine-log}")
    private Integer machineLog;

    @Resource
    private AttendanceMachineLogMapper attendanceMachineLogMapper;

    @Resource
    private AttendanceUserService attendanceUserService;

    @Resource
    private AttendanceGroupMapper attendanceGroupMapper;

    private static final ThreadLocal<AttendanceMachineLog> threadLocal = new ThreadLocal<>();

    @Pointcut("@annotation(jnpf.attendance.annotation.Machine)")
    public void machineLog() {
    }

    @Around(value = "machineLog()")
    public Object generateLog(ProceedingJoinPoint point) throws Throwable {

        if (null == machineLog || machineLog.equals(ConstantUtil.NUM_FALSE)) {
            return point.proceed();
        }
        MethodSignature signature = (MethodSignature) point.getSignature();
        Method method = signature.getMethod();
        Machine annotation = method.getAnnotation(Machine.class);
        Object[] args = point.getArgs();
        ActionEnum actionEnum = annotation.dealAction();
        MachineEnum machineEnum = annotation.factory();
        JSONArray array = new JSONArray();
        AttendanceMachineLog machineLog = new AttendanceMachineLog();
        if (null != args && args.length > 0) {
            String str;
            if (actionEnum.equals(ActionEnum.DA_KA)) {
                str = "arg[0]";
                String paramStr = args[0].toString();
                if (StringUtils.isNotEmpty(paramStr)) {
                    paramStr = paramStr.replaceAll("checkPic=[^,]+,", "");
                    paramStr = paramStr.replaceAll("\"photo\":\"[^\"]*\",", "");
                }
                if (MachineEnum.KE_MI.equals(machineEnum)) {
                    paramStr = JsonUtil.getObjectToString(args[0]);
                }
                MutablePair<String, String> pair = this.getUserInfo(paramStr, machineEnum);
                if (StringUtils.isNotEmpty(pair.getLeft())) {
                    String[] split = pair.getLeft().split("@");
                    String tenantId = split[0];
                    String userId = split[1];
                    // 查询当前考勤组信息
                    UserInfo userInfo = new UserInfo();
                    userInfo.setTenantId(tenantId);
                    userInfo.setUserId(userId);
                    GroupInfoVo group = null;
                    try {
                        List<AttendanceGroupUser> groupList = attendanceUserService.getAttendanceGroupUsersOfSecondment(DateUtil.getNowDate(), DateUtil.getNowDate(), List.of(userId), null, false);
                        if (null != groupList && !groupList.isEmpty()) {
                            String groupName = attendanceGroupMapper.getGroupName(groupList.get(0).getGroupId());
                            group = new GroupInfoVo(groupList.get(0).getGroupId(), groupName);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    machineLog.setUserId(userId);
                    machineLog.setUserName(pair.getRight());
                    if (null != group) {
                        machineLog.setGroupId(group.getGroupId());
                        machineLog.setGroupName(group.getGroupName());
                    }
                }
                JSONObject json = new JSONObject();
                json.set(str, paramStr);
                array.add(json);
            } else {
                for (int i = 0; i < args.length; i++) {
                    str = "arg[" + i + "]";
                    JSONObject json = new JSONObject();
                    try {
                        if (args[i] != null) {
                            if (i == 0) {
                                JSONObject arg = new JSONObject(args[i]);
                                json.set(str, arg.get("userName"));
                                arg.clear();
                            } else {
                                json.set(str, args[i].toString());
                            }
                        } else {
                            json.set(str, "null");
                        }
                    } catch (Exception e) {
                        json.set(str, e.getMessage());
                    }
                    array.add(json);
                }
            }
        }
        machineLog.setId(FtbUtil.getId());
        machineLog.setFactoryCode(machineEnum.getValue());
        machineLog.setAction(actionEnum.getDescription());
        machineLog.setParamJson(array.toString());
        machineLog.setCreatorTime(new Date());
        threadLocal.set(machineLog);
        return point.proceed();
    }

    private MutablePair<String, String> getUserInfo(String paramStr, MachineEnum machineEnum) {

        String userId = null;
        String userName = null;
        String regexUserId;
        String regexUserName;
        switch (machineEnum) {
            case KAI_JIA_YI:
                regexUserId = "\\\"userId\\\":\\\"([^\\\"]*)\\\"";
                regexUserName = "name=(.*?)(,|\\})";
                String regexTenantId = "\\\"tenantId\\\":\\\"([^\\\"]*)\\\"";
                Matcher kjyMatcher = Pattern.compile(regexUserId + "|" + regexUserName + "|" + regexTenantId).matcher(paramStr);
                String tenantId = "";
                while (kjyMatcher.find()) {
                    if (kjyMatcher.group(1) != null) {
                        userId = kjyMatcher.group(1);
                    }
                    if (kjyMatcher.group(2) != null) {
                        userName = kjyMatcher.group(2);
                    }
                    if (kjyMatcher.group(4) != null) {
                        tenantId = kjyMatcher.group(4);
                    }
                }
                userId = tenantId + "@" + userId;
                break;
            case MAO_TONG:
                regexUserId = "user_id=(.*?)(?=,)";
                regexUserName = "user_name=(.*?)(?=,)";
                Matcher matcher = Pattern.compile(regexUserId + "|" + regexUserName).matcher(paramStr);
                while (matcher.find()) {
                    if (matcher.group(1) != null) {
                        userId = matcher.group(1);
                    }
                    if (matcher.group(2) != null) {
                        userName = matcher.group(2);
                    }
                }
                break;
            case KE_MI:
                UserTenantVo userTenant = JsonUtil.getJsonToBean(paramStr, UserTenantVo.class);
                userId = userTenant.getTenantId() + "@" + userTenant.getUserId();
                userName = userTenant.getUserName();
            default:
                break;
        }
        return MutablePair.of(userId, userName);
    }

    @AfterReturning(pointcut = "machineLog()", returning = "result")
    public void afterReturningAdvice(JoinPoint joinPoint, Object result) {

        if (null == machineLog || machineLog.equals(ConstantUtil.NUM_FALSE)) {
            return;
        }
        // 这里可以访问目标方法的返回值
        AttendanceMachineLog machineLog = threadLocal.get();
        if (null != machineLog) {
            machineLog.setMethodResult(null == result ? "无返回值" : result.toString());
            attendanceMachineLogMapper.insert(machineLog);
            threadLocal.remove();
        }
    }

    @AfterThrowing(pointcut = "machineLog()", throwing = "ex")
    public void afterThrowingAdvice(JoinPoint joinPoint, Throwable ex) {

        if (null == machineLog || machineLog.equals(ConstantUtil.NUM_FALSE)) {
            return;
        }
        // 这里可以访问目标方法抛出的异常
        AttendanceMachineLog machineLog = threadLocal.get();
        if (null != machineLog) {
            machineLog.setMethodResult(ex.getMessage());
            attendanceMachineLogMapper.insert(machineLog);
            threadLocal.remove();
        }
    }
}
