package com.easyagents.spring.boot.document.pdf.mineru;

import com.easyagents.document.core.DocumentParseService;
import com.easyagents.document.core.mineru.MineruProperties;
import com.easyagents.document.pdf.PdfDocumentParseService;
import com.easyagents.document.pdf.mineru.MineruPdfDocumentParseService;
import com.easyagents.spring.boot.document.mineru.CommonMineruDocumentProperties;
import com.easyagents.core.util.StringUtil;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

/**
 * MinerU PDF 文档解析自动装配。
 *
 * @author Codex
 * @since 2026-04-14
 */
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(MineruPdfDocumentParseService.class)
@ConditionalOnProperty(prefix = "easy-agents.document.ocr", name = "provider", havingValue = "mineru")
@EnableConfigurationProperties(CommonMineruDocumentProperties.class)
public class MineruPdfAutoConfiguration {

    public static final String DEFAULT_DOCUMENT_PARSE_SERVICE_BEAN_NAME = "documentParseService";

    /**
     * 注册统一 PDF 解析服务。
     *
     * @param commonProperties Spring Boot 配置
     * @return PDF 解析服务
     */
    @Bean
    @Primary
    @ConditionalOnMissingBean(PdfDocumentParseService.class)
    public PdfDocumentParseService pdfDocumentParseService(CommonMineruDocumentProperties commonProperties) {
        return new MineruPdfDocumentParseService(toMineruProperties(commonProperties));
    }

    /**
     * 将默认文档解析服务名注册为 PDF 服务别名，避免重复创建同类型 Bean。
     * 这里显式走 alias，而不是第二个 {@link DocumentParseService} Bean，
     * 这样既能保持默认契约，也不会破坏按 {@link PdfDocumentParseService} 类型的唯一注入。
     *
     * @return BeanFactory 后置处理器
     */
    @Bean
    public static BeanFactoryPostProcessor defaultDocumentParseServiceAliasPostProcessor() {
        return beanFactory -> {
            if (!(beanFactory instanceof BeanDefinitionRegistry)) {
                return;
            }
            BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
            String aliasTarget = resolveAliasTarget(beanFactory, registry);
            if (!StringUtil.hasText(aliasTarget)) {
                return;
            }
            if (registry.containsBeanDefinition(DEFAULT_DOCUMENT_PARSE_SERVICE_BEAN_NAME)
                || registry.isAlias(DEFAULT_DOCUMENT_PARSE_SERVICE_BEAN_NAME)) {
                return;
            }
            if (registry.containsBeanDefinition(aliasTarget)
                && !registry.getBeanDefinition(aliasTarget).isPrimary()) {
                registry.getBeanDefinition(aliasTarget).setPrimary(true);
            }
            registry.registerAlias(aliasTarget, DEFAULT_DOCUMENT_PARSE_SERVICE_BEAN_NAME);
        };
    }

    private static String resolveAliasTarget(org.springframework.beans.factory.config.ConfigurableListableBeanFactory beanFactory,
                                             BeanDefinitionRegistry registry) {
        String[] candidateNames = beanFactory.getBeanNamesForType(PdfDocumentParseService.class, true, false);
        if (candidateNames == null || candidateNames.length == 0) {
            return null;
        }
        if (candidateNames.length == 1) {
            return candidateNames[0];
        }
        String primaryBeanName = null;
        for (String candidateName : candidateNames) {
            if (!registry.containsBeanDefinition(candidateName)) {
                continue;
            }
            if (!registry.getBeanDefinition(candidateName).isPrimary()) {
                continue;
            }
            if (primaryBeanName != null) {
                return null;
            }
            primaryBeanName = candidateName;
        }
        return primaryBeanName;
    }

    private MineruProperties toMineruProperties(CommonMineruDocumentProperties commonProperties) {
        MineruProperties mineruProperties = new MineruProperties();
        boolean useCommon = commonProperties != null && StringUtil.hasText(commonProperties.getBaseUrl());
        mineruProperties.setBaseUrl(useCommon ? commonProperties.getBaseUrl() : null);
        mineruProperties.setConnectTimeoutMs(useCommon ? commonProperties.getConnectTimeoutMs() : null);
        mineruProperties.setReadTimeoutMs(useCommon ? commonProperties.getReadTimeoutMs() : null);
        mineruProperties.setWriteTimeoutMs(useCommon ? commonProperties.getWriteTimeoutMs() : null);
        mineruProperties.setSubmitTimeoutMs(useCommon ? commonProperties.getSubmitTimeoutMs() : null);
        mineruProperties.setPollIntervalMs(useCommon ? commonProperties.getPollIntervalMs() : null);
        mineruProperties.setResultTimeoutMs(useCommon ? commonProperties.getResultTimeoutMs() : null);
        mineruProperties.setDefaultBackend(useCommon ? commonProperties.getDefaultBackend() : null);
        mineruProperties.setDefaultParseMethod(useCommon ? commonProperties.getDefaultParseMethod() : null);
        mineruProperties.setDefaultLangList(useCommon ? commonProperties.getDefaultLangList() : null);
        mineruProperties.setDefaultFormulaEnable(useCommon ? commonProperties.getDefaultFormulaEnable() : null);
        mineruProperties.setDefaultTableEnable(useCommon ? commonProperties.getDefaultTableEnable() : null);
        return mineruProperties;
    }
}
