package com.storlead.sales.config.aspect;


import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.service.IService;
import com.storlead.framework.annotate.Dict;
import com.storlead.framework.util.LoginUserUtil;
import com.storlead.framework.mybatis.service.MyBaseService;
import com.storlead.sales.enums.ResourceTypeEnum;
import com.storlead.sales.service.systemrule.OperationLogService;
import com.storlead.system.pojo.entity.SysDictDetailEntity;
import com.storlead.system.pojo.entity.SysDictEntity;
import com.storlead.system.service.SysDictDetailService;
import com.storlead.system.service.SysDictService;
import io.swagger.annotations.ApiModelProperty;
import lombok.extern.log4j.Log4j2;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

@Log4j2
@Aspect
@Component
public class OperationLogAspect {

    @Resource
    private OperationLogService logService;

    private final Map<Class<?>, MyBaseService<?>> serviceMap = new HashMap<>();

    @Resource
    private SysDictService dictService;

    @Resource
    private SysDictDetailService dictDetailService;

    @Autowired
    public OperationLogAspect(ApplicationContext applicationContext) {
        Map<String, MyBaseService> services = applicationContext.getBeansOfType(MyBaseService.class);
        for (MyBaseService service : services.values()) {
            Class<?> entityType = service.getEntityClass();
            serviceMap.put(entityType, service);
        }
    }

    private Map<String, Object> oldData = new HashMap<>();

    @Pointcut("@annotation(io.swagger.annotations.ApiOperation)")
    public void logPointCut() {
    }

    @Before("execution(* com.storlead.sales..*.updateById(..))")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
        try {
            Object entity = joinPoint.getArgs()[0];
            Class<?> clazz = entity.getClass();
            Field idField = clazz.getDeclaredField("id");
            idField.setAccessible(true);
            Long id = (Long) idField.get(entity);

            IService<?> service = serviceMap.get(clazz);
            if (service != null) {
                Object oldEntity = service.getById(id);
                if (oldEntity != null) {
                    for (Field field : clazz.getDeclaredFields()) {
                        field.setAccessible(true);
                        oldData.put(field.getName(), field.get(oldEntity));
                    }
                }
            }
        }catch (Exception e) {
            log.error("doBefore -error ---",e);
        }
    }

//    @AfterReturning("execution(* com.storlead.frame.mybatis.service.*.updateById(..))")
    @AfterReturning("execution(* com.storlead.sales..*.updateById(..)) || execution(* com.storlead.sales..*.insert(..))")
    public void doAfterReturning(JoinPoint joinPoint) throws Throwable {

        try {
            Object entity = joinPoint.getArgs()[0];
            Class<?> clazz = entity.getClass();
            TableName tableNameAn =  clazz.getAnnotation(TableName.class);
            if (Objects.isNull(tableNameAn)) {
                return;
            }
            Field idField = clazz.getDeclaredField("id");
            idField.setAccessible(true);
            Long id = (Long) idField.get(entity);



            for (Field field : clazz.getDeclaredFields()) {
                field.setAccessible(true);
                Object newValue = field.get(entity);
                Object oldValue = oldData.get(field.getName());
                // 格式化时间类型字段
                newValue = formatFieldValue(field, newValue);
                oldValue = formatFieldValue(field, oldValue);
                //判断是新增还是编辑
                Integer operationType = getOperationType(joinPoint);
                if (operationType == 1){
                    // 在这里排除你不希望拦截的方法
                    String className = joinPoint.getTarget().getClass().getName();
                    String methodName = joinPoint.getSignature().getName();
                    if ("operation_log".equals(tableNameAn.value()) || "sys_operation_log".equals(tableNameAn.value())) {
                        // 记录日志或执行其他操作
                        System.out.println("Method " + methodName + " from class " + className + " has been called.");
                    }else {
                        if (!ObjectUtils.isNull(newValue)) {
                            String apiModelValue = "";
                            // 检查字段上是否有@ApiModelProperty注解
                            if (field.isAnnotationPresent(ApiModelProperty.class)) {
                                ApiModelProperty apiModelProperty = field.getAnnotation(ApiModelProperty.class);
                                // 获取注解中的值，例如value
                                apiModelValue = apiModelProperty.value();
//                                System.out.println("Field Name: " + field.getName() + ", API Model Property Value: " + apiModelValue);
                            }
                            // 检查字段上是否有@Dict注解
                            if (field.isAnnotationPresent(Dict.class)) {
                                Dict dict = AnnotationUtils.getAnnotation(field, Dict.class);
                                Map<String, String> dictMapMap = getDictMap(dict.dictCode());
                                // 获取注解中的值，例如value
                                newValue = dictMapMap.get(String.valueOf(newValue));
                            }
                            if (ResourceTypeEnum.getCodeByValue(tableNameAn.value()) != null) {
                                if (!ObjectUtils.isEmpty(LoginUserUtil.getLoginUser())){
                                    logService.logOperation(tableNameAn.value(), 1, ResourceTypeEnum.getCodeByValue(tableNameAn.value()).toString(), id, field.getName(), apiModelValue, "", String.valueOf(newValue), LoginUserUtil.getLoginUser().getRealName()); // "admin"可替换为实际操作人
                                }else {
                                    logService.logOperation(tableNameAn.value(), 1, ResourceTypeEnum.getCodeByValue(tableNameAn.value()).toString(), id, field.getName(), apiModelValue, "", String.valueOf(newValue), null); // "admin"可替换为实际操作人
                                }

                            }
                        }
                    }
                }else if (operationType == 2){
                    if (newValue != null && !newValue.equals(oldValue)) {
                        String apiModelValue = "";
                        // 检查字段上是否有@ApiModelProperty注解
                        if (field.isAnnotationPresent(ApiModelProperty.class)) {
                            ApiModelProperty apiModelProperty = field.getAnnotation(ApiModelProperty.class);
                            // 获取注解中的值，例如value
                            apiModelValue = apiModelProperty.value();
//                            System.out.println("Field Name: " + field.getName() + ", API Model Property Value: " + apiModelValue);
                        }
                        // 检查字段上是否有@Dict注解
                        if (field.isAnnotationPresent(Dict.class)) {
                            Dict dict = AnnotationUtils.getAnnotation(field, Dict.class);
                            Map<String, String> dictMapMap = getDictMap(dict.dictCode());
                            // 获取注解中的值，例如value
                            oldValue = dictMapMap.get(String.valueOf(oldValue));
                            newValue = dictMapMap.get(String.valueOf(newValue));
                        }
                        if (ResourceTypeEnum.getCodeByValue(tableNameAn.value()) != null) {
                            try {
                                logService.logOperation(tableNameAn.value(), 2, ResourceTypeEnum.getCodeByValue(tableNameAn.value()).toString(), id, field.getName(), apiModelValue, String.valueOf(oldValue), String.valueOf(newValue), LoginUserUtil.getLoginUser().getRealName()); // "admin"可替换为实际操作人
                            }catch (Exception e){
                                log.info("未写入");
                            }

                        }
                    }
                }

            }

            if (ResourceTypeEnum.getCodeByValue(tableNameAn.value()) != null && !tableNameAn.value().equals("customer")) {
                Field customerIdField = clazz.getDeclaredField("customerId");
                customerIdField.setAccessible(true);
                Long customerId = (Long) customerIdField.get(entity);
                if (!ObjectUtils.isEmpty(customerId)){
                    Field nameField = clazz.getDeclaredField(ResourceTypeEnum.getFieldNameByValue(tableNameAn.value()) );
                    nameField.setAccessible(true);
                    String name =  nameField.get(entity).toString();
                    if (!ObjectUtils.isEmpty(LoginUserUtil.getLoginUser())){
                        logService.logOperation("customer", 1, "10", customerId, "", ResourceTypeEnum.getDescByValue(tableNameAn.value()), "", name, LoginUserUtil.getLoginUser().getRealName()); // "admin"可替换为实际操作人
                    }else {
                        logService.logOperation("customer", 1, "10", customerId, "", ResourceTypeEnum.getDescByValue(tableNameAn.value()), "", name, null); // "admin"可替换为实际操作人
                    }

                }

            }
        }catch (Exception e) {
            log.error("doAfterReturning -------error = ",e);
        }

    }

    private Integer getOperationType(JoinPoint joinPoint) {
        Signature signature = joinPoint.getSignature();

        // 判断是否为MethodSignature（因为可能还有其他类型的签名，如ConstructorSignature）
        if (signature instanceof MethodSignature) {
            MethodSignature methodSignature = (MethodSignature) signature;

            // 获取方法名
            String methodName = methodSignature.getMethod().getName();

            // 根据方法名执行不同的逻辑
            if ("updateById".equals(methodName)) {
                // 处理updateById的逻辑
//                System.out.println("Executing updateById method.");
                return 2;
                // ...
            } else if ("insert".equals(methodName)) {
                // 处理insert的逻辑
//                System.out.println("Executing insert method.");
                return 1;
                // ...
            }
        }
        return 0;
    }

    private Map<String, String> getDictMap(String dictCode) {
        QueryWrapper<SysDictEntity> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(SysDictEntity::getCode,dictCode);
        wrapper.last("limit 1");
        SysDictEntity dict = dictService.getOne(wrapper);
        if (Objects.isNull(dict)) {
            return Collections.emptyMap();
        }
        QueryWrapper<SysDictDetailEntity> detailWrapper = new QueryWrapper<>();
        detailWrapper.lambda().eq(SysDictDetailEntity::getDictId,dict.getDictId());
        List<SysDictDetailEntity> detailList = dictDetailService.list(detailWrapper);
        if (CollectionUtils.isEmpty(detailList)) {
            return Collections.emptyMap();
        }
        Map<String, String> dictMap = detailList.stream().collect(Collectors.toMap(SysDictDetailEntity::getValue, SysDictDetailEntity::getLabel, (u1, u2) -> u1));
        return dictMap;
    }

    // 添加字段值格式化方法
    private Object formatFieldValue(Field field, Object value) {
        if (value == null) {
            return null;
        }

        // 获取字段类型
        Class<?> fieldType = field.getType();

        // 处理时间类型字段
        if (isDateTimeType(fieldType)) {
            return formatDateTimeValue(value);
        }

        // 其他类型保持原样
        return value;
    }

    // 判断是否为时间类型
    private boolean isDateTimeType(Class<?> fieldType) {
        return Date.class.isAssignableFrom(fieldType) ||
                LocalDateTime.class.equals(fieldType) ||
                java.sql.Date.class.equals(fieldType) ||
                java.sql.Timestamp.class.equals(fieldType) ||
                java.sql.Time.class.equals(fieldType);
    }

    // 时间类型格式化方法
    private String formatDateTimeValue(Object value) {
        try {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

            if (value instanceof Date) {
                // 处理java.util.Date类型
                Date date = (Date) value;
                return formatter.format(date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime());
            } else if (value instanceof LocalDateTime) {
                // 处理java.time.LocalDateTime类型
                LocalDateTime dateTime = (LocalDateTime) value;
                return dateTime.format(formatter);
            } else if (value instanceof java.sql.Date) {
                // 处理java.sql.Date类型
                java.sql.Date sqlDate = (java.sql.Date) value;
                return formatter.format(sqlDate.toLocalDate().atStartOfDay());
            } else if (value instanceof java.sql.Timestamp) {
                // 处理java.sql.Timestamp类型
                java.sql.Timestamp timestamp = (java.sql.Timestamp) value;
                return timestamp.toLocalDateTime().format(formatter);
            } else if (value instanceof java.sql.Time) {
                // 处理java.sql.Time类型
                java.sql.Time time = (java.sql.Time) value;
                return time.toLocalTime().format(DateTimeFormatter.ofPattern("HH:mm:ss"));
            }
        } catch (Exception e) {
            log.warn("时间格式化失败，字段值: {}", value, e);
        }

        // 格式化失败时返回原始字符串表示
        return String.valueOf(value);
    }


//    private Object getOldEntityById(Class<?> clazz, Long id) {
//        // 根据实际项目需求实现获取旧数据的方法
//        return null;
//    }
}

