package com.qqchen.deploy.backend.framework.config;

import com.qqchen.deploy.backend.framework.controller.BaseController;
import com.qqchen.deploy.backend.framework.converter.BaseConverter;
import com.qqchen.deploy.backend.framework.domain.Entity;
import com.qqchen.deploy.backend.framework.dto.BaseDTO;
import com.qqchen.deploy.backend.framework.enums.ResponseCode;
import com.qqchen.deploy.backend.framework.exception.BusinessException;
import com.qqchen.deploy.backend.framework.exception.DependencyInjectionException;
import com.qqchen.deploy.backend.framework.query.BaseQuery;
import com.qqchen.deploy.backend.framework.repository.IBaseRepository;
import com.qqchen.deploy.backend.framework.service.IBaseService;
import com.qqchen.deploy.backend.framework.service.impl.BaseServiceImpl;
import com.qqchen.deploy.backend.framework.utils.ReflectionUtils;
import com.querydsl.core.types.EntityPath;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.core.GenericTypeResolver;
import org.springframework.stereotype.Component;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@Component
public class DependencyInjectionPostProcessor implements BeanPostProcessor, DisposableBean {

    private final ApplicationContext applicationContext;

    private final Map<Class<?>, IBaseService<?, ?, ?, ?>> serviceCache = new ConcurrentHashMap<>();

    private final Map<Class<?>, IBaseRepository<?, ?>> repositoryCache = new ConcurrentHashMap<>();

    private final Map<Class<?>, BaseConverter<?, ?>> converterCache = new ConcurrentHashMap<>();

    private final Map<Class<?>, EntityPath<?>> entityPathCache = new ConcurrentHashMap<>();

    public DependencyInjectionPostProcessor(ApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        try {
            if (bean instanceof BaseController<?, ?, ?, ?> controller) {
                return injectControllerDependencies(controller, beanName);
            }
            if (bean instanceof BaseServiceImpl<?, ?, ?, ?> service) {
                return injectServiceDependencies(service, beanName);
            }
        } catch (Exception e) {
            String errorMsg = String.format("依赖注入失败 - Bean: %s, 类型: %s, 原因: %s", 
                beanName, bean.getClass().getName(), e.getMessage());
            log.error(errorMsg, e);
            throw new DependencyInjectionException(errorMsg, e);
        }
        return bean;
    }

    // Controller 依赖注入相关方法
    private <T extends Entity<ID>, D extends BaseDTO, Q extends BaseQuery, ID extends Serializable>
    Object injectControllerDependencies(BaseController<T, D, ID, ?> controller, String beanName) {
        Class<T> entityClass = resolveEntityClass(controller);
        if (entityClass == null) {
            return controller;
        }

        IBaseService<?, ?, ?, ?> cachedService = serviceCache.computeIfAbsent(
            entityClass,
            key -> findServiceForEntity(entityClass, beanName)
        );

        try {
            IBaseService<T, D, Q, ID> service = (IBaseService<T, D, Q, ID>) cachedService;
            ReflectionUtils.setField("service", controller, service);
            log.debug("Successfully injected service {} for controller {}",
                service.getClass().getSimpleName(),
                controller.getClass().getSimpleName());
        } catch (Exception e) {
            throw new DependencyInjectionException(
                String.format("Failed to inject service for controller: %s", controller.getClass().getSimpleName()),
                e);
        }

        return controller;
    }

    @SuppressWarnings("unchecked")
    private <T extends Entity<ID>, ID extends Serializable>
    IBaseService<?, ?, ?, ?> findServiceForEntity(Class<T> entityClass, String controllerName) {
        String serviceBeanName = "i" + entityClass.getSimpleName() + "Service";
        log.debug("Looking for service bean: {}", serviceBeanName);

        if (applicationContext.containsBean(serviceBeanName)) {
            return (IBaseService<?, ?, ?, ?>) applicationContext.getBean(serviceBeanName);
        }

        return Arrays.stream(applicationContext.getBeanNamesForType(IBaseService.class))
            .map(name -> tryGetService(name, entityClass, controllerName))
            .filter(Objects::nonNull)
            .findFirst()
            .orElseThrow(() -> new BusinessException(
                ResponseCode.DEPENDENCY_INJECTION_SERVICE_NOT_FOUND,
                new Object[] {entityClass.getSimpleName(), serviceBeanName}));
    }

    @SuppressWarnings("unchecked")
    private <T extends Entity<ID>, ID extends Serializable>
    IBaseService<?, ?, ?, ?> tryGetService(String beanName, Class<T> entityClass, String controllerName) {
        try {
            Class<?> serviceClass = applicationContext.getType(beanName);
            if (serviceClass == null) {
                return null;
            }

            Class<?>[] serviceGenericTypes = GenericTypeResolver.resolveTypeArguments(
                serviceClass, IBaseService.class);

            if (serviceGenericTypes != null &&
                serviceGenericTypes.length > 0 &&
                entityClass.equals(serviceGenericTypes[0])) {
                log.debug("Found matching service: {} for entity: {}", beanName, entityClass.getSimpleName());
                return (IBaseService<?, ?, ?, ?>) applicationContext.getBean(beanName);
            }
        } catch (Exception e) {
            log.warn("Failed to analyze service bean: {} for controller: {}", beanName, controllerName, e);
        }
        return null;
    }

    // Service 依赖注入相关方法
    private <T extends Entity<ID>, D extends BaseDTO, Q extends BaseQuery, ID extends Serializable>
    Object injectServiceDependencies(BaseServiceImpl<T, D, Q, ID> service, String beanName) {
        Class<T> entityClass = resolveEntityClass(service);
        log.debug("Resolving dependencies for entity: {}", entityClass.getSimpleName());

        try {
            injectRepository(service, entityClass);
            injectConverter(service, entityClass);
            injectEntityPath(service, entityClass);

            log.debug("Successfully injected all dependencies for service: {}", beanName);
            return service;
        } catch (Exception e) {
            throw new DependencyInjectionException(
                String.format("Failed to inject dependencies for service: %s", service.getClass().getSimpleName()), e);
        }
    }

    // 通用工具方法
    @SuppressWarnings("unchecked")
    private <T extends Entity<ID>, ID extends Serializable> Class<T> resolveEntityClass(Object bean) {
        Class<?>[] genericTypes = GenericTypeResolver.resolveTypeArguments(
            bean.getClass(), bean instanceof BaseController ? BaseController.class : BaseServiceImpl.class);

        if (genericTypes == null || genericTypes.length < 3) {
            log.warn("Could not resolve entity type for: {}", bean.getClass().getSimpleName());
            return null;
        }

        return (Class<T>) genericTypes[0];
    }

    // ... 其他方法保持不变，但重命名异常类 ...

    @Override
    public void destroy() {
        serviceCache.clear();
        repositoryCache.clear();
        converterCache.clear();
        entityPathCache.clear();
    }

    // 辅助方法，用于注入具体的依赖
    @SuppressWarnings("unchecked")
    private <T extends Entity<ID>, D extends BaseDTO, Q extends BaseQuery, ID extends Serializable>
    void injectRepository(BaseServiceImpl<T, D, Q, ID> service, Class<T> entityClass) {
        String repositoryBeanName = "I" + entityClass.getSimpleName() + "Repository";
        log.debug("正在查找 Repository: {}", repositoryBeanName);

        try {
            IBaseRepository<T, ID> repository = (IBaseRepository<T, ID>) repositoryCache.computeIfAbsent(
                entityClass,
                key -> {
                    if (!applicationContext.containsBean(repositoryBeanName)) {
                        String errorMsg = String.format("找不到 Repository - 服务类: %s, 实体类: %s, Repository名称: %s", service.getClass().getName(), key.getSimpleName(), repositoryBeanName);
                        log.error(errorMsg);
                        throw new DependencyInjectionException(errorMsg, new RuntimeException(errorMsg));
                    }
                    return (IBaseRepository<?, ?>) applicationContext.getBean(repositoryBeanName);
                });

            ReflectionUtils.setField("repository", service, repository);
        } catch (Exception e) {
            String errorMsg = String.format("注入 Repository 失败 - 服务类: %s, 实体类: %s, Repository名称: %s, 原因: %s",
                service.getClass().getName(), entityClass.getSimpleName(), repositoryBeanName, e.getMessage());
            log.error(errorMsg, e);
            throw new DependencyInjectionException(errorMsg, e);
        }
    }

    @SuppressWarnings("unchecked")
    private <T extends Entity<ID>, D extends BaseDTO, Q extends BaseQuery, ID extends Serializable>
    void injectConverter(BaseServiceImpl<T, D, Q, ID> service, Class<T> entityClass) {
        String converterBeanName = entityClass.getSimpleName().substring(0, 1).toLowerCase()
            + entityClass.getSimpleName().substring(1) + "ConverterImpl";
        log.debug("正在查找 Converter: {}", converterBeanName);

        try {
            BaseConverter<T, D> converter = (BaseConverter<T, D>) converterCache.computeIfAbsent(
                entityClass,
                key -> {
                    if (!applicationContext.containsBean(converterBeanName)) {
                        String errorMsg = String.format("找不到 Converter - 服务类: %s, 实体类: %s, Converter名称: %s",
                            service.getClass().getName(), key.getSimpleName(), converterBeanName);
                        log.error(errorMsg);
                        throw new DependencyInjectionException(errorMsg, new RuntimeException(errorMsg));
                    }
                    return (BaseConverter<?, ?>) applicationContext.getBean(converterBeanName);
                });

            ReflectionUtils.setField("converter", service, converter);
        } catch (Exception e) {
            String errorMsg = String.format("注入 Converter 失败 - 服务类: %s, 实体类: %s, Converter名称: %s, 原因: %s",
                service.getClass().getName(), entityClass.getSimpleName(), converterBeanName, e.getMessage());
            log.error(errorMsg, e);
            throw new DependencyInjectionException(errorMsg, e);
        }
    }

    @SuppressWarnings("unchecked")
    private <T extends Entity<ID>, D extends BaseDTO, Q extends BaseQuery, ID extends Serializable>
    void injectEntityPath(BaseServiceImpl<T, D, Q, ID> service, Class<T> entityClass) {
        try {
            EntityPath<T> entityPath = (EntityPath<T>) entityPathCache.computeIfAbsent(
                entityClass,
                key -> {
                    String qClassName = key.getPackageName() + ".Q" + key.getSimpleName();
                    try {
                        Class<?> qClass = Class.forName(qClassName);
                        String fieldName = key.getSimpleName();
                        fieldName = fieldName.substring(0, 1).toLowerCase() + fieldName.substring(1);
                        Field instanceField = qClass.getDeclaredField(fieldName);
                        return (EntityPath<?>) instanceField.get(null);
                    } catch (ClassNotFoundException e) {
                        String errorMsg = String.format("找不到 QueryDSL 实体类 - 服务类: %s, 实体类: %s, Q类名: %s",
                            service.getClass().getName(), key.getSimpleName(), qClassName);
                        log.error(errorMsg, e);
                        throw new DependencyInjectionException(errorMsg, e);
                    } catch (NoSuchFieldException e) {
                        String errorMsg = String.format("找不到 QueryDSL 实体字段 - 服务类: %s, 实体类: %s, Q类名: %s",
                            service.getClass().getName(), key.getSimpleName(), qClassName);
                        log.error(errorMsg, e);
                        throw new DependencyInjectionException(errorMsg, e);
                    } catch (Exception e) {
                        String errorMsg = String.format("获取 QueryDSL 实体失败 - 服务类: %s, 实体类: %s, Q类名: %s, 原因: %s",
                            service.getClass().getName(), key.getSimpleName(), qClassName, e.getMessage());
                        log.error(errorMsg, e);
                        throw new DependencyInjectionException(errorMsg, e);
                    }
                });

            ReflectionUtils.setField("entityPath", service, entityPath);
        } catch (Exception e) {
            String errorMsg = String.format("注入 EntityPath 失败 - 服务类: %s, 实体类: %s, 原因: %s",
                service.getClass().getName(), entityClass.getSimpleName(), e.getMessage());
            log.error(errorMsg, e);
            throw new DependencyInjectionException(errorMsg, e);
        }
    }
} 