package click.kamil.springstatemachineexporter.ast.common;

import org.eclipse.jdt.core.dom.*;
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 ControlFlowGraphTest {

    @Test
    void testSequentialAndBranchingCfg(@TempDir Path tempDir) throws IOException {
        Path comFoo = tempDir.resolve("com/foo");
        Files.createDirectories(comFoo);
        Files.writeString(comFoo.resolve("Test.java"),
            "package com.foo;\n" +
            "public class Test {\n" +
            "    public void run(boolean flag) {\n" +
            "        int a = 1;\n" +
            "        if (flag) {\n" +
            "            a = 2;\n" +
            "        } else {\n" +
            "            a = 3;\n" +
            "        }\n" +
            "        int b = a;\n" +
            "    }\n" +
            "}"
        );

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

        TypeDeclaration td = context.getTypeDeclaration("com.foo.Test");
        assertThat(td).isNotNull();

        MethodDeclaration md = td.getMethods()[0];
        ControlFlowGraph cfg = CfgBuilder.build(md);
        
        assertThat(cfg).isNotNull();
        assertThat(cfg.getEntryNode().getSuccessors()).hasSize(1);
        
        // Entry goes to first statement: 'int a = 1;'
        ControlFlowGraph.CfgNode firstStmtNode = cfg.getEntryNode().getSuccessors().iterator().next();
        assertThat(firstStmtNode.getAstNode()).isInstanceOf(VariableDeclarationStatement.class);

        // First stmt goes to condition of 'if (flag)'
        assertThat(firstStmtNode.getSuccessors()).hasSize(1);
        ControlFlowGraph.CfgNode condNode = firstStmtNode.getSuccessors().iterator().next();
        assertThat(condNode.getAstNode()).isInstanceOf(SimpleName.class); // flag
        
        // Cond node goes to two branches: 'a = 2;' and 'a = 3;'
        assertThat(condNode.getSuccessors()).hasSize(2);

        for (ControlFlowGraph.CfgNode branchSuccessor : condNode.getSuccessors()) {
            assertThat(branchSuccessor.getAstNode()).isInstanceOf(ExpressionStatement.class); // assignment expression statement
            
            // Each branch successor should flow into the next sequential statement: 'int b = a;'
            assertThat(branchSuccessor.getSuccessors()).hasSize(1);
            ControlFlowGraph.CfgNode nextStmtNode = branchSuccessor.getSuccessors().iterator().next();
            assertThat(nextStmtNode.getAstNode()).isInstanceOf(VariableDeclarationStatement.class);
            assertThat(nextStmtNode.getSuccessors()).contains(cfg.getExitNode());
        }
    }
}
