package click.kamil.springstatemachineexporter.analysis.model;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import lombok.Builder;
import lombok.Data;
import lombok.extern.jackson.Jacksonized;

import java.util.Map;

@Data
@Builder(toBuilder = true)
@Jacksonized
@JsonIgnoreProperties(ignoreUnknown = true)
public class TriggerPoint {
    private String event;
    private final String className;
    private final String methodName;
    private final String sourceFile;
    private final String sourceModule;
    private final String stateMachineId; // Optional: to link to a specific SM instance
    private final String sourceState;    // Optional: if we can determine the expected current state
    private final int lineNumber;
    @com.fasterxml.jackson.annotation.JsonIgnore
    private final String stateTypeFqn;  // Type of State (e.g. OrderStates FQN)
    @com.fasterxml.jackson.annotation.JsonIgnore
    private final String eventTypeFqn;  // Type of Event (e.g. OrderEvents FQN)
    private final java.util.List<String> polymorphicEvents; // NEW: stores concrete events resolved via deep polymorphism
    private final boolean external;
    private final String constraint;
    private final boolean ambiguous;

    public TriggerPoint(
            String event,
            String className,
            String methodName,
            String sourceFile,
            String sourceModule,
            String stateMachineId,
            String sourceState,
            int lineNumber,
            String stateTypeFqn,
            String eventTypeFqn,
            java.util.List<String> polymorphicEvents,
            boolean external,
            String constraint,
            boolean ambiguous) {
        this.className = className;
        this.methodName = methodName;
        this.sourceFile = sourceFile;
        this.sourceModule = sourceModule;
        this.stateMachineId = stateMachineId;
        this.sourceState = sourceState;
        this.lineNumber = lineNumber;
        this.stateTypeFqn = stateTypeFqn;
        this.eventTypeFqn = eventTypeFqn;
        this.event = qualifyEvent(event, eventTypeFqn);
        if (polymorphicEvents != null) {
            this.polymorphicEvents = polymorphicEvents.stream()
                    .map(pe -> qualifyEvent(pe, eventTypeFqn))
                    .collect(java.util.stream.Collectors.toList());
        } else {
            this.polymorphicEvents = null;
        }
        this.external = external;
        this.constraint = constraint;
        this.ambiguous = ambiguous;
    }

    private static String qualifyEvent(String e, String eventTypeFqn) {
        if (e == null || eventTypeFqn == null || e.isEmpty()) {
            return e;
        }
        if (e.startsWith("<SYMBOLIC: ")) {
            return e;
        }
        if (isWildcardVariable(e)) {
            return e;
        }
        if (Character.isLowerCase(e.charAt(0))) {
            return e;
        }
        if (!isEnumConstantCandidate(e)) {
            return e;
        }

        String simpleEventType = eventTypeFqn.contains(".") ? eventTypeFqn.substring(eventTypeFqn.lastIndexOf('.') + 1) : eventTypeFqn;

        if (e.contains(".")) {
            String qualifier = e.substring(0, e.lastIndexOf('.'));
            String lastSegment = e.substring(e.lastIndexOf('.') + 1);
            String simpleQualifier = qualifier.contains(".") ? qualifier.substring(qualifier.lastIndexOf('.') + 1) : qualifier;

            if (simpleQualifier.equals(simpleEventType)) {
                return simpleEventType + "." + lastSegment;
            }
            return e;
        }
        if (eventTypeFqn.startsWith("java.lang.") || eventTypeFqn.equals("String") || eventTypeFqn.equals("int") || eventTypeFqn.equals("long") || eventTypeFqn.equals("char")) {
            return e;
        }
        return simpleEventType + "." + e;
    }

    private static boolean isEnumConstantCandidate(String eventStr) {
        if (eventStr == null) return false;
        if (eventStr.startsWith("<SYMBOLIC: ")) {
            return false;
        }
        if (eventStr.contains(" ") || eventStr.contains("(") || eventStr.contains(")") || eventStr.contains("?")) {
            return false;
        }
        return true;
    }

    private static boolean isWildcardVariable(String eventStr) {
        if (eventStr == null) return false;
        if (eventStr.equals("event") || eventStr.equals("e") || 
            eventStr.equals("msg") || eventStr.equals("message") || 
            eventStr.equals("payload")) {
            return true;
        }
        if (eventStr.contains(".valueOf(") || eventStr.contains("valueOf (")) {
            return true;
        }
        if (eventStr.contains(" ? ") && eventStr.contains(" : ")) {
            return true;
        }
        return false;
    }
}
