package ai.intelliswarm.swarmai.state.question;

import java.time.Instant;
import java.util.List;
import java.util.Objects;
import java.util.UUID;

/**
 * A structured question the agent has paused to ask the user. Distinct from a
 * tool call (no side effect), distinct from a system reminder (the user is
 * <em>required</em> to respond). The harness presents the question via a
 * {@link UserQuestionResolver}, blocks the agent's tool-call return until an
 * answer is provided, then surfaces the answer back to the LLM as the tool's
 * output string.
 *
 * <p>SwarmAI's structured user-question primitive (analogous to
 * an "ask user question" tool). Use it when:
 * <ul>
 *   <li>A decision can't be inferred from prior context (e.g. "should I fix
 *       this in main or in a feature branch?")</li>
 *   <li>The agent has multiple valid paths and the user is the only authority
 *       (e.g. "which deployment target?")</li>
 *   <li>You want explicit human approval routing without changing tool behaviour
 *       (the user-question hook lives entirely in the agent's tool layer)</li>
 * </ul>
 *
 * @param id            autogenerated UUID — never null
 * @param question      the prompt shown to the user; never null or blank
 * @param options       optional list of pre-defined choices; if non-empty and
 *                      {@code allowFreeform} is false, the user must pick one
 * @param allowFreeform when true, the user may type a custom answer even if
 *                      {@code options} is non-empty
 * @param askedAt       when the question was created
 */
public record UserQuestion(
        String id,
        String question,
        List<String> options,
        boolean allowFreeform,
        Instant askedAt) {

    public UserQuestion {
        Objects.requireNonNull(id, "id");
        Objects.requireNonNull(question, "question");
        if (question.isBlank()) {
            throw new IllegalArgumentException("question must not be blank");
        }
        if (options == null) {
            options = List.of();
        } else {
            for (String opt : options) {
                if (opt == null || opt.isBlank()) {
                    throw new IllegalArgumentException("option must not be null or blank");
                }
            }
            options = List.copyOf(options);
        }
        if (askedAt == null) askedAt = Instant.now();
        // If options is empty, freeform is implicitly required regardless of flag.
    }

    /** Convenience: a freeform question with no pre-defined options. */
    public static UserQuestion freeform(String question) {
        return new UserQuestion(UUID.randomUUID().toString(), question,
                List.of(), true, Instant.now());
    }

    /** Convenience: a multiple-choice question with no freeform fallback. */
    public static UserQuestion choose(String question, List<String> options) {
        return new UserQuestion(UUID.randomUUID().toString(), question,
                options, false, Instant.now());
    }

    /** Convenience: choices + the user may also type a custom answer. */
    public static UserQuestion chooseOrFreeform(String question, List<String> options) {
        return new UserQuestion(UUID.randomUUID().toString(), question,
                options, true, Instant.now());
    }

    /** True when no pre-defined options are present (freeform required). */
    public boolean isFreeformOnly() {
        return options.isEmpty();
    }
}
