package click.kamil.springstatemachineexporter.analysis.resolver;

import click.kamil.springstatemachineexporter.ast.common.CodebaseContext;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.ReturnStatement;
import org.eclipse.jdt.core.dom.SwitchExpression;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.JavaCore;
import org.junit.jupiter.api.Test;

import java.util.Map;

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

class ConstantResolverSwitchPolicyTest {

    @Test
    void boundSelectorMustNotTakeDefaultWhenCaseMatched() {
        String source = """
            package com.example;
            class M {
              Object map(String commandKey) {
                return switch (commandKey) {
                  case "order.pay" -> DomainCommand.ORDER_PAY;
                  case "order.ship" -> DomainCommand.ORDER_SHIP;
                  default -> DomainCommand.ORDER_CANCEL;
                };
              }
            }
            enum DomainCommand { ORDER_PAY, ORDER_SHIP, ORDER_CANCEL }
            """;
        SwitchExpression se = firstReturnedSwitch(source);
        ConstantResolver cr = new ConstantResolver();
        CodebaseContext ctx = new CodebaseContext();
        String resolved = cr.evaluateSwitchWithParams(se, Map.of("commandKey", "order.pay"), ctx);
        assertThat(resolved).isEqualTo("DomainCommand.ORDER_PAY");
    }

    @Test
    void unboundIdentitySelectorYieldsEnumSetNotLastWins() {
        String source = """
            package com.example;
            class M {
              Object map(String type) {
                return switch (type) {
                  case "a" -> "PAY";
                  case "b" -> "SHIP";
                  default -> { yield "CANCEL"; }
                };
              }
            }
            """;
        SwitchExpression se = firstReturnedSwitch(source);
        ConstantResolver cr = new ConstantResolver();
        String resolved = cr.evaluateSwitchWithParams(se, Map.of(), new CodebaseContext());
        assertThat(resolved).startsWith("ENUM_SET:");
        assertThat(resolved).contains("PAY", "SHIP", "CANCEL");
    }

    private static SwitchExpression firstReturnedSwitch(String source) {
        ASTParser parser = ASTParser.newParser(AST.JLS17);
        Map<String, String> options = JavaCore.getOptions();
        JavaCore.setComplianceOptions(JavaCore.VERSION_17, options);
        parser.setCompilerOptions(options);
        parser.setKind(ASTParser.K_COMPILATION_UNIT);
        parser.setSource(source.toCharArray());
        CompilationUnit cu = (CompilationUnit) parser.createAST(null);
        TypeDeclaration td = (TypeDeclaration) cu.types().get(0);
        MethodDeclaration md = td.getMethods()[0];
        ReturnStatement rs = (ReturnStatement) md.getBody().statements().get(0);
        ASTNode expr = rs.getExpression();
        while (expr instanceof org.eclipse.jdt.core.dom.ParenthesizedExpression pe) {
            expr = pe.getExpression();
        }
        return (SwitchExpression) expr;
    }
}
