package click.kamil.springstatemachineexporter.analysis.spring;

import click.kamil.springstatemachineexporter.analysis.service.ToolingClasspath;
import click.kamil.springstatemachineexporter.ast.common.CodebaseContext;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import static org.assertj.core.api.Assertions.assertThat;

class SpringContextScannerIntegrationTest {

    private CodebaseContext context;
    private SpringBeanRegistry registry;

    @BeforeEach
    void setUp() throws IOException {
        Path projectRoot = Path.of("../state_machines/extended_analysis_sample").toAbsolutePath().normalize();
        
        context = new CodebaseContext();
        context.setProjectRoot(projectRoot);
        context.setSourcepath(List.of(projectRoot.resolve("src/main/java").toString()));
        context.setClasspath(ToolingClasspath.currentJvmJarEntries());
        context.setResolveBindings(true);
        
        context.scan(Set.of(projectRoot), Collections.emptySet());
        
        registry = new SpringBeanRegistry();
        SpringContextScanner scanner = new SpringContextScanner(registry);
        
        for (var cu : context.getCompilationUnits()) {
            cu.accept(scanner);
        }
    }

    @Test
    void shouldFindStereotypeBeans() {
        List<SpringBean> beans = registry.getBeans();
        
        // PrimaryQuirkService
        assertThat(beans).anySatisfy(bean -> {
            assertThat(bean.getTypeFqn()).isEqualTo("click.kamil.examples.statemachine.extended.service.PrimaryQuirkService");
            assertThat(bean.isPrimary()).isTrue();
            assertThat(bean.getAssignableTypes()).contains("click.kamil.examples.statemachine.extended.service.QuirkService");
            assertThat(bean.getBeanNames()).contains("primaryQuirkService");
        });
        
        // QualifierQuirkService
        assertThat(beans).anySatisfy(bean -> {
            assertThat(bean.getTypeFqn()).isEqualTo("click.kamil.examples.statemachine.extended.service.QualifierQuirkService");
            assertThat(bean.isPrimary()).isFalse();
            assertThat(bean.getBeanNames()).contains("qualifierQuirkService");
        });
        
        // NamedQuirkService (should have explicit name via @Service("customName"))
        assertThat(beans).anySatisfy(bean -> {
            assertThat(bean.getTypeFqn()).isEqualTo("click.kamil.examples.statemachine.extended.service.NamedQuirkService");
            assertThat(bean.getBeanNames()).contains("customName");
        });

        // PaymentController (should be detected via @RestController)
        assertThat(beans).anySatisfy(bean -> {
            assertThat(bean.getTypeFqn()).isEqualTo("click.kamil.examples.statemachine.extended.web.PaymentController");
        });
    }

    @Test
    void shouldFindMethodBeans() {
        List<SpringBean> beans = registry.getBeans();
        
        // Beans created via @Bean
        assertThat(beans).anySatisfy(bean -> {
            assertThat(bean.getTypeFqn()).isEqualTo("java.lang.String");
            assertThat(bean.getFactoryMethodName()).isEqualTo("myStringBean");
            assertThat(bean.getBeanNames()).contains("customMockBean");
            assertThat(bean.getDeclaringClassFqn()).isEqualTo("click.kamil.examples.statemachine.extended.config.MockBeanConfig");
        });
    }
}
