package click.kamil.springstatemachineexporter.analysis.service;

import click.kamil.springstatemachineexporter.analysis.model.CallChain;
import click.kamil.springstatemachineexporter.analysis.model.EntryPoint;
import click.kamil.springstatemachineexporter.analysis.model.TriggerPoint;
import click.kamil.springstatemachineexporter.ast.common.CodebaseContext;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;

class BuilderLocalVariableTest {

    @Test
    void shouldTraceLocalVariableInBuilderPattern(@TempDir Path tempDir) throws IOException {
        String source = """
                package com.example;
                public class OrderController {
                    private OrderService service;
                    public void processOrderEvent() {
                        OrderEvents e = OrderEvents.PAY;
                        RichOrderEvent event = new RichOrderEvent();
                        event.setType(e);
                        service.updateOrderState(event.getType());
                    }
                }
                
                class OrderService {
                    public void updateOrderState(OrderEvents event) {}
                }
                
                class RichOrderEvent {
                    private OrderEvents type;
                    public void setType(OrderEvents type) { this.type = type; }
                    public OrderEvents getType() { return type; }
                }
                
                enum OrderEvents { PAY }
                """;
        Files.writeString(tempDir.resolve("OrderConfig.java"), source);

        CodebaseContext context = new CodebaseContext();
        context.scan(tempDir);

        HeuristicCallGraphEngine builder = new HeuristicCallGraphEngine(context);

        EntryPoint entryPoint = EntryPoint.builder()
                .className("com.example.OrderController")
                .methodName("processOrderEvent")
                .build();

        TriggerPoint trigger = TriggerPoint.builder()
                .className("com.example.OrderService")
                .methodName("updateOrderState")
                .event("event")
                .build();

        List<CallChain> chains = builder.findChains(List.of(entryPoint), List.of(trigger));

        assertThat(chains).hasSize(1);
        CallChain chain = chains.get(0);
        System.out.println("POLY EVENTS FOUND: " + chain.getTriggerPoint().getPolymorphicEvents());
        assertThat(chain.getTriggerPoint().getPolymorphicEvents())
            .containsExactlyInAnyOrder("OrderEvents.PAY");
    }

    @Test
    void shouldTraceFluentBuilder(@TempDir Path tempDir) throws IOException {
        String source = """
                package com.example;
                public class MyController {
                    private MyService service;
                    public void processEvent() {
                        MyEvent event = MyEvent.builder().type(MyEnum.STATE_2).build();
                        service.process(event.getType());
                    }
                }
                
                class MyService {
                    public void process(MyEnum event) {}
                }
                
                class MyEvent {
                    private MyEnum type;
                    public static Builder builder() { return new Builder(); }
                    public MyEnum getType() { return type; }
                    public static class Builder {
                        private MyEnum type;
                        public Builder type(MyEnum type) { this.type = type; return this; }
                        public MyEvent build() { return new MyEvent(); }
                    }
                }
                
                enum MyEnum { STATE_1, STATE_2 }
                """;
        Files.writeString(tempDir.resolve("MyConfig.java"), source);

        CodebaseContext context = new CodebaseContext();
        context.scan(tempDir);

        HeuristicCallGraphEngine builder = new HeuristicCallGraphEngine(context);

        EntryPoint entryPoint = EntryPoint.builder()
                .className("com.example.MyController")
                .methodName("processEvent")
                .build();

        TriggerPoint trigger = TriggerPoint.builder()
                .className("com.example.MyService")
                .methodName("process")
                .event("event")
                .build();

        List<CallChain> chains = builder.findChains(List.of(entryPoint), List.of(trigger));

        assertThat(chains).hasSize(1);
        CallChain chain = chains.get(0);
        assertThat(chain.getTriggerPoint().getPolymorphicEvents())
            .containsExactlyInAnyOrder("MyEnum.STATE_2");
    }
}
