

package com.ainovel.server.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.ReactiveMongoDatabaseFactory;
import org.springframework.data.mongodb.ReactiveMongoTransactionManager;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
import org.springframework.data.mongodb.core.SimpleReactiveMongoDatabaseFactory;
import org.springframework.data.mongodb.core.convert.MongoCustomConversions;
import org.springframework.data.mongodb.core.convert.MappingMongoConverter;
import org.springframework.data.mongodb.repository.config.EnableReactiveMongoRepositories;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.mongodb.ConnectionString;
import com.mongodb.MongoClientSettings;
import com.mongodb.reactivestreams.client.MongoClient;
import com.mongodb.reactivestreams.client.MongoClients;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.convert.ReadingConverter;
import org.springframework.data.convert.WritingConverter;

import java.time.Instant;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
// import java.util.Map; // 移除通用Map转换后不再需要

/**
 * MongoDB配置类
 * 配置MongoDB连接、响应式支持、日志和统计功能
 */
@Configuration
@EnableReactiveMongoRepositories(basePackages = "com.ainovel.server.repository")
@EnableMongoRepositories(basePackages = "com.ainovel.server.repository")
public class MongoConfig {
    
    private static final Logger logger = LoggerFactory.getLogger(MongoConfig.class);
    
    @Value("${spring.data.mongodb.uri}")
    private String mongoUri;
    
    @Value("${spring.data.mongodb.database}")
    private String database;
    
    // 注意：这里不注入全局 ObjectMapper 以避免误用于通用 Map 转换
    public MongoConfig() {}
    
    /**
     * 创建MongoDB事件监听器，用于记录MongoDB操作日志
     * 注释掉以减少日志输出
     */
    // @Bean
    // public LoggingEventListener mongoEventListener() {
    //     return new LoggingEventListener();
    // }
    
    /**
     * 创建MongoDB映射调试监听器
     * 注释掉以减少日志输出
     */
    // @Bean
    // public AbstractMongoEventListener<Object> mongoMappingDebugListener() {
    //     return new AbstractMongoEventListener<Object>() {
    //         @Override
    //         public void onAfterLoad(AfterLoadEvent<Object> event) {
    //             if (logger.isTraceEnabled()) {
    //                 logger.trace("📥 MongoDB加载文档: collection={}, document={}", 
    //                     event.getCollectionName(), event.getDocument().keySet());
    //             }
    //         }
    //     };
    // }
    
    /**
     * 自定义ReactiveMongoTemplate，添加查询统计和日志功能
     * @param factory MongoDB数据库工厂
     * @param mappingMongoConverter 自定义的映射转换器（包含点号替换配置）
     * @return 自定义的ReactiveMongoTemplate
     */
    @Bean
    public ReactiveMongoTemplate reactiveMongoTemplate(ReactiveMongoDatabaseFactory factory, 
                                                       MappingMongoConverter mappingMongoConverter) {
        // 使用构造函数直接传入自定义的MappingMongoConverter
        ReactiveMongoTemplate template = new ReactiveMongoTemplate(factory, mappingMongoConverter);
        
        // 启用日志记录
        logger.info("✅ 已配置ReactiveMongoTemplate，使用自定义MappingMongoConverter（支持点号替换）");
        return template;
    }
    
    /**
     * 创建MongoDB客户端，添加性能监控
     * @return MongoDB客户端
     */
    @Bean
    public MongoClient reactiveMongoClient() {
        ConnectionString connectionString = new ConnectionString(mongoUri);
        
        MongoClientSettings settings = MongoClientSettings.builder()
                .applyConnectionString(connectionString)
                .applicationName("AINovalWriter")
                .build();
        
        logger.info("创建MongoDB客户端，连接到: {}", database);
        return MongoClients.create(settings);
    }
    
    /**
     * 创建MongoDB数据库工厂
     * @param mongoClient MongoDB客户端
     * @return MongoDB数据库工厂
     */
    @Bean
    public ReactiveMongoDatabaseFactory reactiveMongoDatabaseFactory(MongoClient mongoClient) {
        return new SimpleReactiveMongoDatabaseFactory(mongoClient, database);
    }
    
    /**
     * 创建MongoDB事务管理器
     * @param dbFactory MongoDB数据库工厂
     * @return MongoDB事务管理器
     */
    @Bean
    public ReactiveMongoTransactionManager transactionManager(ReactiveMongoDatabaseFactory dbFactory) {
        return new ReactiveMongoTransactionManager(dbFactory);
    }
    
    /**
     * 配置自定义MongoDB转换器
     * @return 自定义转换器配置
     */
    @Bean
    public MongoCustomConversions mongoCustomConversions(SafeMapConverter safeMapConverter) {
        List<Converter<?, ?>> converters = new ArrayList<>();
        
        // 日期/时间转换器
        converters.add(new DateToInstantConverter());
        converters.add(new InstantToDateConverter());
        
        // 仅保留安全的Map读取与时间类型转换，避免过于宽泛的 Map<->Object 转换导致的Spring Data WARN
        
        // 安全的Map转换器 - 处理类型不匹配问题
        converters.add(safeMapConverter);
        
        logger.info("MongoDB自定义转换器配置完成，总计 {} 个转换器", converters.size());
        
        return new MongoCustomConversions(converters);
    }
    
    /**
     * 配置专门的MongoDB ObjectMapper来处理序列化/反序列化
     * 确保与JsonCreator注解配合工作，解决复杂嵌套对象映射问题
     */
    @Bean("mongoObjectMapper")
    public ObjectMapper mongoObjectMapper() {
        ObjectMapper mapper = new ObjectMapper();
        
        // 注册JavaTime模块
        mapper.registerModule(new JavaTimeModule());
        
        // 配置反序列化行为
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false);
        mapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true);
        
        logger.info("MongoDB ObjectMapper配置完成，支持JsonCreator构造函数映射");
        
        return mapper;
    }
    
    /**
     * Date到Instant的转换器
     */
    @ReadingConverter
    public static class DateToInstantConverter implements Converter<Date, Instant> {
        @Override
        public Instant convert(Date source) {
            return source == null ? null : source.toInstant();
        }
    }
    
    /**
     * Instant到Date的转换器
     */
    @WritingConverter
    public static class InstantToDateConverter implements Converter<Instant, Date> {
        @Override
        public Date convert(Instant source) {
            return source == null ? null : Date.from(source);
        }
    }
    
    // 注意：通用的 Map<->Object 转换改由业务层的 TaskConversionConfig 控制，
    // 避免在全局转换器中过于宽泛，导致Spring Data发出非存储类型转换的警告。
} 