package com.iqser.red.service.persistence.service.v1.api.external.resource;

import java.util.List;

import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.multipart.MultipartFile;

import com.iqser.red.service.persistence.service.v1.api.shared.model.CreateTypeValue;
import com.iqser.red.service.persistence.service.v1.api.shared.model.Dictionary;
import com.iqser.red.service.persistence.service.v1.api.shared.model.TypeResponse;
import com.iqser.red.service.persistence.service.v1.api.shared.model.TypeValue;
import com.iqser.red.service.persistence.service.v1.api.shared.model.UpdateTypeValue;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.configuration.Colors;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.type.DictionaryEntryType;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;

@ResponseStatus(value = HttpStatus.OK)
public interface DictionaryResource {

    String DICTIONARY_REST_PATH = ExternalApi.BASE_PATH + "/dictionary";
    String TYPE_PATH = DICTIONARY_REST_PATH + "/type";

    String TYPE_PARAMETER_NAME = "type";
    String TYPE_PATH_VARIABLE = "/{" + TYPE_PARAMETER_NAME + "}";

    String REMOVE_CURRENT_REQUEST_PARAM = "removeCurrent";

    String ENTRY_PARAMETER_NAME = "entry";
    String ENTRY_PATH_VARIABLE = "/{" + ENTRY_PARAMETER_NAME + "}";

    String DOSSIER_TEMPLATE_PARAMETER_NAME = "dossierTemplateId";
    String DOSSIER_TEMPLATE_PATH_VARIABLE = "/{dossierTemplateId}";

    String UPLOAD = "/upload";
    String DOWNLOAD = "/download";
    String MERGED = "/merged";
    String DELETE = "/delete";

    String COLOR_REST_PATH = ExternalApi.BASE_PATH + "/color";

    String DOSSIER_ID_PARAMETER_NAME = "dossierId";

    String INCLUDE_DELETED_PARAMETER_NAME = "includeDeleted";

    String DICTIONARY_ENTRY_TYPE_PARAM = "dictionaryEntryType";
    String DEFAULT_DICTIONARY_ENTRY_TYPE = "ENTRY";


    @ResponseStatus(HttpStatus.NO_CONTENT)
    @PostMapping(value = DICTIONARY_REST_PATH + TYPE_PATH_VARIABLE + DOSSIER_TEMPLATE_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE)
    @Operation(summary = "Add dictionary entries with entry type.", description = "None")
    @ApiResponses(value = {@ApiResponse(responseCode = "204", description = "Successfully added the dictionary entries."), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The " + "entry type is not found.")})
    void addEntry(@PathVariable(TYPE_PARAMETER_NAME) String type,
                  @PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId,
                  @RequestBody List<String> entries,
                  @RequestParam(name = REMOVE_CURRENT_REQUEST_PARAM, defaultValue = "false", required = false) boolean removeCurrent,
                  @RequestParam(value = DOSSIER_ID_PARAMETER_NAME, required = false) String dossierId,
                  @RequestParam(value = DICTIONARY_ENTRY_TYPE_PARAM, required = false, defaultValue = DEFAULT_DICTIONARY_ENTRY_TYPE) DictionaryEntryType dictionaryEntryType);


    @ResponseStatus(HttpStatus.NO_CONTENT)
    @PostMapping(value = DICTIONARY_REST_PATH + DELETE + TYPE_PATH_VARIABLE + DOSSIER_TEMPLATE_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE)
    @Operation(summary = "Delete dictionary entries with entry type.", description = "None")
    @ApiResponses(value = {@ApiResponse(responseCode = "204", description = "Successfully deleted the dictionary entries."), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The " + "entry type is not found.")})
    void deleteEntries(@PathVariable(TYPE_PARAMETER_NAME) String type,
                       @PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId,
                       @RequestBody List<String> entries,
                       @RequestParam(value = DOSSIER_ID_PARAMETER_NAME, required = false) String dossierId,
                       @RequestParam(value = DICTIONARY_ENTRY_TYPE_PARAM, required = false, defaultValue = DEFAULT_DICTIONARY_ENTRY_TYPE) DictionaryEntryType dictionaryEntryType);


    @ResponseStatus(HttpStatus.NO_CONTENT)
    @DeleteMapping(value = DICTIONARY_REST_PATH + TYPE_PATH_VARIABLE + DOSSIER_TEMPLATE_PATH_VARIABLE + ENTRY_PATH_VARIABLE)
    @Operation(summary = "Delete dictionary entry with entry type.", description = "None")
    @ApiResponses(value = {@ApiResponse(responseCode = "204", description = "Successfully deleted the dictionary entry."), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The " + "entry type is not found.")})
    void deleteEntry(@PathVariable(TYPE_PARAMETER_NAME) String type,
                     @PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId,
                     @PathVariable(ENTRY_PARAMETER_NAME) String entry,
                     @RequestParam(value = DOSSIER_ID_PARAMETER_NAME, required = false) String dossierId,
                     @RequestParam(value = DICTIONARY_ENTRY_TYPE_PARAM, required = false, defaultValue = DEFAULT_DICTIONARY_ENTRY_TYPE) DictionaryEntryType dictionaryEntryType);


    @ResponseStatus(HttpStatus.NO_CONTENT)
    @PostMapping(value = TYPE_PATH + TYPE_PATH_VARIABLE + DOSSIER_TEMPLATE_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE)
    @Operation(summary = "Updates colors, hint and caseInsensitive of an entry type. Only label, colors and description are updatable for system managed entry types", description = "None")
    @ApiResponses(value = {@ApiResponse(responseCode = "204", description = "Successfully updated the colors, hint and caseInsensitive of entry type"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The entry type is not found.")})
    void updateType(@PathVariable(TYPE_PARAMETER_NAME) String type,
                    @PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId,
                    @RequestBody UpdateTypeValue typeValue);


    @ResponseStatus(HttpStatus.OK)
    @PostMapping(value = TYPE_PATH, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    @Operation(summary = "Creates entry type with colors, hint and caseInsensitive", description = "None")
    @ApiResponses(value = {@ApiResponse(responseCode = "204", description = "Successfully created the entry type with colors, hint " + "and caseInsensitive"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "409", description = "The entry type already exists, could not be added again.")})
    TypeValue addType(@RequestBody CreateTypeValue typeValue);


    @ResponseStatus(HttpStatus.NO_CONTENT)
    @DeleteMapping(value = TYPE_PATH + TYPE_PATH_VARIABLE + DOSSIER_TEMPLATE_PATH_VARIABLE)
    @Operation(summary = "Deletes entry type", description = "None")
    @ApiResponses(value = {@ApiResponse(responseCode = "204", description = "Successfully deleted the entry type with value and all its entries"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The entry type is not found.")})
    void deleteType(@PathVariable(TYPE_PARAMETER_NAME) String type,
                    @PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId);


    @ResponseStatus(HttpStatus.NO_CONTENT)
    @PostMapping(value = TYPE_PATH + DOSSIER_TEMPLATE_PATH_VARIABLE + DELETE)
    @Operation(summary = "Deletes entry types", description = "None")
    @ApiResponses(value = {@ApiResponse(responseCode = "204", description = "Successfully deleted the entry types with value and all their entries"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The entry type is not found.")})
    void deleteTypes(@RequestBody List<String> types,
                     @PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId);


    @GetMapping(value = TYPE_PATH + DOSSIER_TEMPLATE_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE)
    @Operation(summary = "Retrieve all entry types", description = "None")
    @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Successfully retrieved all the entry types")})
    TypeResponse getAllTypes(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId,
                             @RequestParam(value = DOSSIER_ID_PARAMETER_NAME, required = false) String dossierId,
                             @RequestParam(value = INCLUDE_DELETED_PARAMETER_NAME, required = false, defaultValue = "false") boolean includeDeleted);


    @GetMapping(value = DICTIONARY_REST_PATH + TYPE_PATH_VARIABLE + DOSSIER_TEMPLATE_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE)
    @Operation(summary = "Retrieves all dictionary entries of an entry type", description = "None")
    @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Successfully retrieved all the dictionary entries of " + "the entry type."), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The entry type is not found.")})
    Dictionary getDictionaryForType(@PathVariable(TYPE_PARAMETER_NAME) String type,
                                    @PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId,
                                    @RequestParam(value = DOSSIER_ID_PARAMETER_NAME, required = false) String dossierId);


    /**
     * Upload dictionary for given type as file to be used by redaction service.
     *
     * @param file Text file containing dictionary entries as plain text.
     * @param type Type of dictionary entries inside given file.
     */
    @ResponseStatus(value = HttpStatus.NO_CONTENT)
    @PostMapping(value = DICTIONARY_REST_PATH + UPLOAD + TYPE_PATH_VARIABLE + DOSSIER_TEMPLATE_PATH_VARIABLE, consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    @Operation(summary = "Upload a text-file with 1 entry per line and add each line as an entry to a dictionary for a specific type")
    @ApiResponses(value = {@ApiResponse(responseCode = "204", description = "Dictionary upload successful."), @ApiResponse(responseCode = "400", description = "Dictionary could not be uploaded.")})
    void uploadDictionary(@RequestPart(name = "file", required = false) MultipartFile file,
                          @PathVariable(TYPE_PARAMETER_NAME) String type,
                          @PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId,
                          @RequestParam(value = DOSSIER_ID_PARAMETER_NAME, required = false) String dossierId,
                          @RequestParam(value = DICTIONARY_ENTRY_TYPE_PARAM, required = false, defaultValue = DEFAULT_DICTIONARY_ENTRY_TYPE) DictionaryEntryType dictionaryEntryType);


    /**
     * Download dictionary for given type as file.
     *
     * @param type Type of dictionary entries inside requested file.
     */
    @ResponseBody
    @Operation(summary = "Returns file containing the the dictionary entries for given type..")
    @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
    @GetMapping(value = DICTIONARY_REST_PATH + DOWNLOAD + TYPE_PATH_VARIABLE + DOSSIER_TEMPLATE_PATH_VARIABLE)
    ResponseEntity<?> downloadDictionary(@PathVariable(TYPE_PARAMETER_NAME) String type,
                                         @PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId,
                                         @RequestParam(value = DOSSIER_ID_PARAMETER_NAME, required = false) String dossierId,
                                         @RequestParam(value = DICTIONARY_ENTRY_TYPE_PARAM, required = false, defaultValue = DEFAULT_DICTIONARY_ENTRY_TYPE) DictionaryEntryType dictionaryEntryType);

    @GetMapping(value = DICTIONARY_REST_PATH + MERGED + TYPE_PATH_VARIABLE+ DOSSIER_TEMPLATE_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE)
    @Operation(summary = "Retrieves the merged dictionary  for the given type, dossier template and dossier", description = "None")
    @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Successfully retrieved all the dictionary entries"), @ApiResponse(responseCode = "400", description = "Request contains error."), @ApiResponse(responseCode = "404", description = "The entry type is not found.")})
    Dictionary getMergedDictionaries(@PathVariable(TYPE_PARAMETER_NAME) String type,
                                           @PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId,
                                           @RequestParam(value = DOSSIER_ID_PARAMETER_NAME) String dossierId);

    @ResponseStatus(HttpStatus.NO_CONTENT)
    @Operation(summary = "Set system colors for redaction")
    @ApiResponses(value = {@ApiResponse(responseCode = "204", description = "System colors update successful."), @ApiResponse(responseCode = "400", description = "System colors request contains error.")})
    @PostMapping(value = COLOR_REST_PATH + DOSSIER_TEMPLATE_PATH_VARIABLE, consumes = MediaType.APPLICATION_JSON_VALUE)
    void setColors(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId, @RequestBody Colors colors);


    @ResponseBody
    @Operation(summary = "Retrieves system colors for redaction.", description = "None")
    @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Successfully retrieved system colors for redaction."), @ApiResponse(responseCode = "404", description = "The system colors is not found.")})
    @GetMapping(value = COLOR_REST_PATH + DOSSIER_TEMPLATE_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE)
    Colors getColors(@PathVariable(DOSSIER_TEMPLATE_PARAMETER_NAME) String dossierTemplateId);

}
