package cn.iocoder.yudao.framework.mybatis.core.util;

import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.reflect.MethodUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.time.*;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class AutoQueryUtil {

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

    /**
     * 根据实体类的属性值是否为空自动创建LambdaQueryWrapper。
     *
     * @param entity 实体对象
     * @param <T>    实体类型
     * @return LambdaQueryWrapper
     */
    public static <T> QueryWrapper<T> autoQuery(T entity) {
        QueryWrapper<T> queryWrapper = new QueryWrapper<>();
        if (entity == null) {
            return queryWrapper;
        }

        Class<?> clazz = entity.getClass();
        // 遍历当前类和所有父类的字段
        while (clazz != null) {
            Map<String, Method> getterMethods = new HashMap<>();
            for (Field field : clazz.getDeclaredFields()) {
                field.setAccessible(true);
                String fieldName = field.getName();
                Class<?> finalClazz = clazz;
                Method getterMethod = getterMethods.computeIfAbsent(
                    "get" + capitalize(fieldName),
                    k -> {
                        try {
                            return MethodUtils.getAccessibleMethod(finalClazz, k, (Class<?>[]) null);
                        } catch (Exception e) {
                            log.error("No such getter method: {}", k, e);
                            return null;
                        }
                    }
                );

                if (getterMethod != null) {
                    try {
                        Object value = getterMethod.invoke(entity);
                        if (value != null && !"".equals(value)) {
                            handleFieldValue(queryWrapper, field, value);
                        }
                    } catch (Exception e) {
                        log.error("Error invoking getter method: {}", getterMethod.getName(), e);
                    }
                }
            }
            // 获取父类，继续遍历父类的字段
            clazz = clazz.getSuperclass();
        }

        return queryWrapper;
    }

    public static String getTenantId(){
        HttpServletRequest request = ServletUtils.getRequest();
        if (null != request) {
            // 获取request的header中的x-tenant-id
            String tenantId = ServletUtils.getHeader(request, "x-tenant-id");
            if (StringUtils.isNotBlank(tenantId)) {
                return tenantId;
            }
        }
        return null;
    }

    private static void handleFieldValue(QueryWrapper<?> queryWrapper, Field field, Object value) {
        String fieldName = field.getName();

        if (String.class.isAssignableFrom(field.getType())) {
            queryWrapper.like(StrUtil.toUnderlineCase(fieldName), value);
        } else if (Integer.class.isAssignableFrom(field.getType()) ||
            Long.class.isAssignableFrom(field.getType()) ||
            Double.class.isAssignableFrom(field.getType()) ||
            Float.class.isAssignableFrom(field.getType()) ||
            Boolean.class.isAssignableFrom(field.getType()) ||
            Short.class.isAssignableFrom(field.getType()) ||
            Byte.class.isAssignableFrom(field.getType()) ||
            Character.class.isAssignableFrom(field.getType()) ||
            Date.class.isAssignableFrom(field.getType()) ||
            LocalDateTime.class.isAssignableFrom(field.getType()) ||
            LocalDate.class.isAssignableFrom(field.getType()) ||
            LocalTime.class.isAssignableFrom(field.getType()) ||
            ZonedDateTime.class.isAssignableFrom(field.getType()) ||
            Instant.class.isAssignableFrom(field.getType())) {
            queryWrapper.eq(StrUtil.toUnderlineCase(fieldName), String.valueOf(value));
        } else {
            // 如果是其他类型，可以添加更多条件，或者忽略
            log.warn("Unsupported field type: {}", field.getType().getName());
        }
    }

    /**
     * 获取 pageReqVO 中所有 LocalDate[]、LocalDateTime[] 和 Date[] 类型字段的名称
     */
    public static String[] getDateRangeFieldNames(Object pageReqVO) {
        return Arrays.stream(pageReqVO.getClass().getDeclaredFields())
            .filter(field -> field.getType().equals(LocalDate[].class)
                || field.getType().equals(LocalDateTime[].class)
                || field.getType().equals(Date[].class))
            .map(Field::getName)
            .toArray(String[]::new);
    }

    /**
     * 动态处理 pageReqVO 中所有 LocalDate[]、LocalDateTime[] 和 Date[] 类型字段，设置时间段查询条件
     */
    public static void handleDateRangeFields(Object pageReqVO, QueryWrapper<?> queryWrapper) {
        for (Field field : pageReqVO.getClass().getDeclaredFields()) {
            field.setAccessible(true);
            try {
                Object fieldValue = field.get(pageReqVO);
                if (fieldValue == null) {
                    continue; // 跳过值为 null 的字段
                }

                if (field.getType().equals(LocalDate[].class)) {
                    LocalDate[] dateRange = (LocalDate[]) fieldValue;
                    if (dateRange.length == 2) {
                        String columnName = StrUtil.toUnderlineCase(field.getName()); // 字段名转换为数据库列名
                        queryWrapper.between(columnName, dateRange[0], dateRange[1]);
                    }
                } else if (field.getType().equals(LocalDateTime[].class)) {
                    LocalDateTime[] dateTimeRange = (LocalDateTime[]) fieldValue;
                    if (dateTimeRange.length == 2) {
                        String columnName = StrUtil.toUnderlineCase(field.getName()); // 字段名转换为数据库列名
                        queryWrapper.between(columnName, dateTimeRange[0], dateTimeRange[1]);
                    }
                } else if (field.getType().equals(Date[].class)) {
                    Date[] range = (Date[]) fieldValue;
                    if (range.length == 2) {
                        String columnName = StrUtil.toUnderlineCase(field.getName()); // 字段名转换为数据库列名
                        queryWrapper.between(columnName, range[0], range[1]);
                    }
                }
            } catch (IllegalAccessException e) {
                throw new ServiceException(500,"Failed to access field " + field.getName() + ": " + e.getMessage());
            }
        }
    }

    private static String capitalize(String str) {
        return str.substring(0, 1).toUpperCase() + str.substring(1);
    }
}
