/*
 * RiskScape™ Copyright New Zealand Institute for Earth Science Limited
 * (Earth Sciences New Zealand) is distributed for research purposes only
 * under the terms of AGPLv3.
 *
 * RiskScape™ Copyright 2026 New Zealand Institute for Earth Science
 * Limited (Earth Sciences New Zealand). All rights reserved. Source code
 * available under the AGPLv3.
 * 
 * This program is free software: you can redistribute it and/or modify it under
 *  the terms of the GNU Affero General Public License as published by the Free
 *  Software Foundation, either version 3 of the License, or (at your option) any
 *  later version.
 * 
 * This program is distributed for RESEARCH PURPOSES ONLY, in the hope that it will
 * be useful for research and education initiatives.
 * 
 * If you are not a researcher, or you are a researcher who wishes to use this
 * program on terms other than AGPLv3 (including those who wish to restrict the
 * distribution of any source code created using this program), please contact:
 * https://riskscape.org.nz
 * 
 * This program is distributed WITHOUT ANY WARRANTY; without even the implied
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Affero General Public License for more details.  You should have received a copy
 * of the GNU Affero General Public License along with this program.  If not, see
 * <http://www.gnu.org/licenses/>.
 * 
 * By way of summary only, under the AGPLv3:
 *     • Permissions of this strongest copyleft license are conditioned
 *       on making available complete source code of licensed works and
 *       modifications, which include larger works using a licensed work,
 *       under the same license.
 *     • Copyright and license notices must be preserved.
 *     • Contributors provide an express grant of patent rights.
 *     • When a modified version is used to provide a service over a
 *       network, the complete source code of the modified version must be made
 *       available.
 */
package nz.org.riskscape.wizard;

import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Optional;

import nz.org.riskscape.engine.i18n.MutableMessageSource;
import nz.org.riskscape.rl.ast.PipelineDeclaration;
import nz.org.riskscape.wizard.bld.IncrementalBuildState;
import nz.org.riskscape.wizard.bld.PipelineChange;
import nz.org.riskscape.wizard.survey2.Phase;

/**
 * A {@link QuestionSet} is a part of a {@link Survey} that groups together some questions that can apply a
 * functionally similar set of changes to a {@link PipelineDeclaration}.  The {@link QuestionSet} 'drives' the survey
 * by offering {@link Question}s to the user and then plugging the answers in to update the {@link PipelineDeclaration},
 * via the {@link IncrementalBuildState}
 */
public interface QuestionSet {

  /**
   * Used as a unique question to act as a place for a final change to hang from - it needs a unique question for the
   * change to hang from, otherwise {@link IncrementalBuildState#append(PipelineChange,
   * nz.org.riskscape.rl.ast.PipelineDeclaration, nz.org.riskscape.engine.pipeline.RealizedPipeline)} will
   * complain.
   */
  Question FINAL_QUESTION = new Question("finish", Void.class).optionalOne();

  /**
   * Used when a Question belongs to nothing (yet)
   */
  QuestionSet UNASSIGNED = new EmptyQuestionSet("unassigned", new EmptySurvey("empty", new MutableMessageSource()));

  /**
   * Presented to the user as a choice when optional QuestionSets can be skipped.
   */
  QuestionSet SKIP = new EmptyQuestionSet("skip", new EmptySurvey("empty", new MutableMessageSource()));

  /**
   * @return a String that uniquely identifies this QuestionSet
   * TODO this might become a name and end up being a weak identifier, as the name is probably only unique within the
   * context of a survey
   */
  String getId();

  /**
   * A human-friendly title for this QuestionSet
   */
  Optional<String> getTitle(Locale locale);

  /**
   * A human-friendly description for this QuestionSet
   */
  Optional<String> getDescription(Locale locale);

  /**
   * Returns a {@link PipelineChange} that is created by applying an answer a build state.
   * @param buildState the build state to get a change to.
   * @param answer the answer to apply.  This answer must be for a question that came back from
   * {@link #getNextQuestions(IncrementalBuildState)} using the given build state, or weird things might happen
   */
  PipelineChange getPipelineChange(IncrementalBuildState buildState, Answer answer);

  /**
   * @return the survey to which this set belongs
   */
  Survey getSurvey();

  /**
   * The list of questions that this question set contains.
   *
   * These questions should be partially ordered such that if question `b` comes after question `a` then they should be
   * ordered so that `a` is before b in the list.
   *
   * Previously, there was potential for this list to change as the build state changed, and so this method was removed
   * from the QuestionSet interface.  But this possibility is being dropped with the new survey2 api in favour of a
   * static list of questions per set, but allowing a dynamic set of question sets.
   *
   */
  default List<Question> getQuestions() {
    return Collections.emptyList();
  }

  default String getName() {
    return getId();
  }

  /**
   * @return the phase this QuestionSet belongs to
   */
  Phase getPhase();

}
