package com.atlassian.bitbucket.ui;

import javax.annotation.Nonnull;
import java.io.IOException;
import java.util.Collection;
import java.util.Map;

/**
 * Allows the injection of fields into existing forms provided by the host application.
 *
 * @see PluginFormFragments
 */
public interface ContextualFormFragment {

    /**
     * @param appendable the {@link Appendable} to append field HTML that will be injected into the form. The fields
     *                   should match the style of the pre-existing fields in the form.
     * @param context map with relevant contextual objects
     * @throws java.io.IOException if there was a problem writing to the supplied appendable.
     */
    void doView(@Nonnull Appendable appendable, @Nonnull Map<String, Object> context) throws IOException;

    /**
     * Validate the fields supplied by this form fragment. This method <em>should not</em> persist any field values, as
     * validation may fail on another field not specified by this {@link ContextualFormFragment}.
     * See {@link #execute(Map, Map)}, which is invoked after {@link #validate(Map, ValidationErrors, Map)} if all
     * fragments have successfully validated. This method should make all
     * reasonable attempts to ensure that the subsequent invocation of {@link #execute(Map, Map)} will not fail.
     *
     * @param requestParams the map of parameters from the request. This will contain any input supplied by the user in
     *                      the fields rendered by {@link #doView}, alongside any other fields in the form rendered by
     *                      the system or other {@link ContextualFormFragment}s.
     * @param errors use this to report any validation errors on the input supplied from your fields. See
     *               {@link ValidationErrors} for more details.
     * @param context map with relevant contextual objects
     */
    void validate(@Nonnull Map<String, String[]> requestParams, @Nonnull ValidationErrors errors,
                  @Nonnull Map<String, Object> context);

    /**
     * Render your fields after a validation error has occurred. Note that the validation error may have occurred on a
     * field not supplied by this {@link ContextualFormFragment}.
     *
     * @param requestParams the map of parameters from the request. This will contain any input supplied by the user in
     *                      the fields rendered by {@link #doView}, alongside any other fields in the form rendered by
     *                      the system or other {@link ContextualFormFragment}s.
     * @param fieldErrors a {@link java.util.Map} of String field names to sets of String error messages. If the field name
     *                    matches one of the fields supplied by your {@link #doView} implementation, you should render
     *                    the error messages alongside your field.
     * @param appendable the {@link Appendable} to append field HTML that will be injected into the form, with any
     *                   relevant errors supplied by the fieldErrors map rendered inline. The fields and error messaging
     *                   should match the style of the pre-existing fields in the form.
     * @param context map with relevant contextual objects
     * @throws java.io.IOException if there was a problem writing to the supplied appendable.
     */
    void doError(@Nonnull Appendable appendable, @Nonnull Map<String, String[]> requestParams,
                 @Nonnull Map<String, Collection<String>> fieldErrors, @Nonnull Map<String, Object> context) throws IOException;

    /**
     * Store the fields supplied by this form and perform any other actions. Any failures at this point are considered
     * unrecoverable and should throw an unchecked exception to halt the request (which will redirect the user to a 500
     * page). Any recoverable errors should be handled above in the {@link #validate} method.
     *
     * This method is invoked only if the {@link #validate} method on all registered {@link ContextualFormFragment}s and the
     * form's own field validation has completed without any validation errors.
     *
     * @param requestParams the map of parameters from the request. This will contain any input supplied by the user in
     *                      the fields rendered by {@link #doView}, alongside any other fields in the form rendered by
     *                      the system or other {@link ContextualFormFragment}s.
     * @param context       a map of contextual objects that can be used by the form fragment implementation, such as
     *                      the project, repository or pull request if relevant.
     */
    void execute(@Nonnull Map<String, String[]> requestParams, @Nonnull Map<String, Object> context);

}