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

import com.iqser.red.service.persistence.service.v1.api.shared.model.FileAttributes;
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileStatus;
import com.iqser.red.service.persistence.service.v1.api.shared.model.FileUploadResult;
import com.iqser.red.service.persistence.service.v2.api.external.model.FileDeleteRequest;
import com.iqser.red.service.persistence.service.v2.api.external.model.FileStatusList;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import static com.iqser.red.service.persistence.service.v2.api.external.resource.DossierResource.*;
import static com.iqser.red.service.persistence.service.v2.api.external.resource.DossierTemplateResource.*;

@ApiResponses(value = {@ApiResponse(responseCode = "429", description = "Too many requests.")})
public interface FileResource {

    String FILE_PATH = "/files";
    String PATH = ExternalApiConstants.BASE_PATH + DOSSIER_TEMPLATE_PATH + DOSSIER_TEMPLATE_ID_PATH_VARIABLE + DOSSIER_PATH + DOSSIER_ID_PATH_PARAM + FILE_PATH;
    String BULK_DELETE_PATH = "/bulk/delete";
    String FILE_ATTRIBUTES_PATH = "/attributes";
    String KEEP_MANUAL_CHANGES_PARAM = "keepManualChanges";
    String DELETE_PERMANENTLY_PARAM = "deletePermanently";
    String FILE_PARAM = "file";
    String FILE_ID_PARAM = "fileId";
    String FILE_ID_PATH_VARIABLE = "/{" + FILE_ID_PARAM + "}";


    @ResponseBody
    @ResponseStatus(value = HttpStatus.CREATED)
    @PostMapping(value = PATH, consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    @Operation(summary = "Upload a file for a specific dossier.", description = "The multipart file upload returns the identifier for the uploaded file. If the dossier contains a file with the same name, it will be overwritten. Supported file types are PDF documents, Microsoft Office documents, and CSV files. Microsoft office files (file extensions `docx`, `xlsx`, or `pptx`) will be converted into PDF documents. Please note that the generated PDF might look slightly different to the original as the system does not necessarily have all fonts. However, it will generate an output on best effort to stay as close to the original as possible. CSV files are used to support a bulk annotation of file attributes. If the dossier is configured in a way to map specific fields of the CSV to file attributes and the CSV matches the mapped structure, the system will process the file or ignore it otherwise.")
    @ApiResponses(value = {@ApiResponse(responseCode = "201", description = "File upload succeeded. Return the fileId of the uploaded file.")})
    FileUploadResult upload(@Parameter(name = DOSSIER_TEMPLATE_ID_PARAM, description = "The identifier of the dossier template that is used for the dossier.", required = true) @PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
                            @Parameter(name = DOSSIER_ID_PARAM, description = "The identifier of the dossier to where the file is to be uploaded.", required = true) @PathVariable(DOSSIER_ID_PARAM) String dossierId,
                            @Parameter(name = FILE_PARAM, description = "The file to be uploaded.", required = true) @RequestPart(name = FILE_PARAM) MultipartFile file,
                            @Parameter(name = DOSSIER_ID_PARAM, description = "A Toggle to keep manual changes: Manual changes are manually added annotations or manipulations on existing ones. If set to `true` the system keeps the manual changes on re-uploading (overwriting) the file.") @RequestParam(value = KEEP_MANUAL_CHANGES_PARAM, required = false, defaultValue = "false") boolean keepManualChanges);

    @ResponseStatus(value = HttpStatus.OK)
    @ResponseBody
    @GetMapping(value = PATH, produces = MediaType.APPLICATION_JSON_VALUE)
    @Operation(summary = "Gets the status for all files in a dossier.", description = "The status contains information like ... By default, only the status of active files is returned. There are several parameters that can be combined to change the response scope.")
    @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
    FileStatusList getDossierStatus(@Parameter(name = DOSSIER_TEMPLATE_ID_PARAM, description = "The identifier of the dossier template that is used for the dossier.", required = true) @PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
                                    @Parameter(name = DOSSIER_ID_PARAM, description = "The identifier of the dossier containing the file of which the status is requested.", required = true) @PathVariable(DOSSIER_ID_PARAM) String dossierId,
                                    @Parameter(name = INCLUDE_ACTIVE_PARAM, description = "A Toggle to include active files: If `true` (default) the response contains the status of files that are active, i.e. they are not soft-deleted.") @RequestParam(name = INCLUDE_ACTIVE_PARAM, defaultValue = "true", required = false) boolean includeActive,
                                    @Parameter(name = INCLUDE_ARCHIVED_PARAM, description = "A Toggle to include files of archived dossiers: If `true` the response contains the status of files that belong to an archived dossier. Set to `false` if you expect a `404 Not found` if the dossier is archived.") @RequestParam(name = INCLUDE_ARCHIVED_PARAM, defaultValue = "false", required = false) boolean includeArchived,
                                    @Parameter(name = INCLUDE_SOFT_DELETED_PARAM, description = "A Toggle to include soft-deleted dossiers and files: If `true` the response contains the status of files that have been soft-deleted, i.e. the files can still be restored.") @RequestParam(name = INCLUDE_SOFT_DELETED_PARAM, defaultValue = "false", required = false) boolean includeSoftDeleted);


    @ResponseStatus(value = HttpStatus.OK)
    @ResponseBody
    @GetMapping(value = PATH + FILE_ID_PATH_VARIABLE, produces = MediaType.APPLICATION_JSON_VALUE)
    @Operation(summary = "Gets the status for a file.", description = "None")
    @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "Not found")})
    FileStatus getFileStatus(@Parameter(name = DOSSIER_TEMPLATE_ID_PARAM, description = "The identifier of the dossier template that is used for the dossier.", required = true) @PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
                             @Parameter(name = DOSSIER_ID_PARAM, description = "The identifier of the dossier containing the file of which the status is requested.", required = true) @PathVariable(DOSSIER_ID_PARAM) String dossierId,
                             @Parameter(name = FILE_ID_PARAM, description = "The identifier of the file of which the status is requested.", required = true) @PathVariable(FILE_ID_PARAM) String fileId,
                             @Parameter(name = INCLUDE_ACTIVE_PARAM, description = "A Toggle to include active files: If `true` (default) the response contains the status of files that are active, i.e. they are not soft-deleted.") @RequestParam(name = INCLUDE_ACTIVE_PARAM, defaultValue = "true", required = false) boolean includeActive,
                             @Parameter(name = INCLUDE_ARCHIVED_PARAM, description = "A Toggle to include files of archived dossiers: If `true` the response contains the status of files that belong to an archived dossier. Set to `false` if you expect a `404 Not found` if the dossier is archived.") @RequestParam(name = INCLUDE_ARCHIVED_PARAM, defaultValue = "false", required = false) boolean includeArchived,
                             @Parameter(name = INCLUDE_SOFT_DELETED_PARAM, description = "A Toggle to include soft-deleted dossiers and files: If `true` the response contains the status of files that have been soft-deleted, i.e. the files can still be restored.") @RequestParam(name = INCLUDE_SOFT_DELETED_PARAM, defaultValue = "false", required = false) boolean includeSoftDeleted);


    @ResponseStatus(value = HttpStatus.NO_CONTENT)
    @DeleteMapping(value = PATH + FILE_ID_PATH_VARIABLE)
    @Operation(summary = "Deletes a file for a given dossierId and FileId", description = "When deleting a file, it gets 'soft-deleted' by default, i.e. it can be restored within retention time configured in the dossier template. There is a toggle to also permanently delete the file.")
    @ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK")})
    void deleteFile(@Parameter(name = DOSSIER_TEMPLATE_ID_PARAM, description = "The identifier of the dossier template that is used for the dossier.", required = true) @PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
                    @Parameter(name = DOSSIER_ID_PARAM, description = "The identifier of the dossier that contains the file.", required = true) @PathVariable(DOSSIER_ID_PARAM) String dossierId,
                    @Parameter(name = FILE_ID_PARAM, description = "The identifier of the file that will be deleted.", required = true) @PathVariable(FILE_ID_PARAM) String fileId,
                    @Parameter(name = DELETE_PERMANENTLY_PARAM, description = "A Toggle to permanently delete the file: If `true` the file will be deleted permanently, i.e. in contrast to a soft-delete (value is `false`) the file cannot be restored anymore. This can be applied also on previously soft-deleted files.") @RequestParam(name = DELETE_PERMANENTLY_PARAM, defaultValue = "false", required = false) boolean deletePermanently);


    @ResponseStatus(value = HttpStatus.NO_CONTENT)
    @PostMapping(value = PATH + BULK_DELETE_PATH)
    @Operation(summary = "Deletes a list of files of a specific dossier (DELETE with body payload)", description = "None")
    @ApiResponses(value = {@ApiResponse(responseCode = "204", description = "OK")})
    void deleteFiles(@Parameter(name = DOSSIER_TEMPLATE_ID_PARAM, description = "The identifier of the dossier template that is used for the dossier.", required = true) @PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
                     @Parameter(name = DOSSIER_ID_PARAM, description = "The identifier of the dossier that contains the file.", required = true) @PathVariable(DOSSIER_ID_PARAM) String dossierId,
                     @RequestBody FileDeleteRequest fileDeleteRequest,
                     @Parameter(name = DELETE_PERMANENTLY_PARAM, description = "A Toggle to permanently delete the file: If `true` the file will be deleted permanently, i.e. in contrast to a soft-delete (value is `false`) the file cannot be restored anymore. This can be applied also on previously soft-deleted files.") @RequestParam(name = DELETE_PERMANENTLY_PARAM, defaultValue = "false", required = false) boolean deletePermanently);


    @Operation(summary = "Set file attributes to an existing file", description = "None")
    @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
    @PostMapping(value = PATH + FILE_ID_PATH_VARIABLE + FILE_ATTRIBUTES_PATH, consumes = MediaType.APPLICATION_JSON_VALUE)
    void setFileAttributes(@Parameter(name = DOSSIER_TEMPLATE_ID_PARAM, description = "The identifier of the dossier template that is used for the dossier.", required = true) @PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
                           @Parameter(name = DOSSIER_ID_PARAM, description = "The identifier of the dossier that contains the file.", required = true) @PathVariable(DOSSIER_ID_PARAM) String dossierId,
                           @Parameter(name = FILE_ID_PARAM, description = "The identifier of the file of which the file attributes are set.", required = true) @PathVariable(FILE_ID_PARAM) String fileId,
                           @RequestBody FileAttributes fileAttributes);

}
