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

import java.time.OffsetDateTime;
import java.util.List;
import java.util.Set;

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.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierChangeEntry;
import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierInformation;
import com.iqser.red.service.persistence.service.v1.api.shared.model.DossierRequest;
import com.iqser.red.service.persistence.service.v1.api.shared.model.common.JSONPrimitive;
import com.iqser.red.service.persistence.service.v1.api.shared.model.dossiertemplate.dossier.Dossier;

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

public interface DossierResource {

    String DOSSIER_REST_PATH = ExternalApi.BASE_PATH + "/dossier";
    String DOSSIER_TEMPLATE_PATH = "/dossier-template";
    String DOSSIER_INFO_PATH = "/info";
    String DELETED_DOSSIERS_PATH = ExternalApi.BASE_PATH + "/deleted-dossiers";
    String CHANGES_DETAILS_PATH = "/changes/details";
    String HARD_DELETE_PATH = "/hard-delete";
    String UNDELETE_PATH = "/restore";

    String ARCHIVE_DOSSIERS_PATH = ExternalApi.BASE_PATH + "/archived-dossiers";
    String ARCHIVE_PATH = "/archive";
    String UNARCHIVE_PATH = "/unarchive";

    String DOSSIER_ID_PARAM = "dossierId";
    String DOSSIER_ID_PATH_PARAM = "/{" + DOSSIER_ID_PARAM + "}";
    String DOSSIER_TEMPLATE_ID_PARAM = "dossierTemplateId";
    String DOSSIER_TEMPLATE_ID_PATH_PARAM = "/{" + DOSSIER_TEMPLATE_ID_PARAM + "}";

    String INCLUDE_DELETED_PARAM = "includeDeleted";
    String INCLUDE_ARCHIVED_PARAM = "includeArchived";


    @ResponseBody
    @PostMapping(value = DOSSIER_REST_PATH + DOSSIER_INFO_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
    @Operation(summary = "Get information regarding the count of dossiers", description = "None")
    @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Success")})
    DossierInformation getDossierInformation();


    @ResponseBody
    @PostMapping(value = DOSSIER_REST_PATH + CHANGES_DETAILS_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
    @Operation(summary = "See if there are changes to dossiers since param", description = "None")
    @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "Success")})
    List<DossierChangeEntry> changesSince(@RequestBody JSONPrimitive<OffsetDateTime> since);


    @ResponseBody
    @PostMapping(value = DOSSIER_REST_PATH, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
    @Operation(summary = "Creates or updates a dossier.", description = "None")
    @ApiResponses(value = {@ApiResponse(responseCode = "201", description = "Successfully saved the dossier."), @ApiResponse(responseCode = "400", description = "Incorrect dossier ID provided or attempted to change dossier-template for a dossier with files."), @ApiResponse(responseCode = "409", description = "Duplicate")})
    ResponseEntity<Dossier> createDossierOrUpdateDossier(@RequestBody DossierRequest dossier);


    @ResponseStatus(value = HttpStatus.NO_CONTENT)
    @DeleteMapping(value = DOSSIER_REST_PATH + DOSSIER_ID_PATH_PARAM)
    @Operation(summary = "Deletes an existing dossier.", description = "None")
    @ApiResponses(value = {@ApiResponse(responseCode = "204", description = "Successfully deleted the dossier."), @ApiResponse(responseCode = "404", description = "Not found")})
    void deleteDossier(@PathVariable(DOSSIER_ID_PARAM) String dossierId);


    @ResponseStatus(value = HttpStatus.OK)
    @ResponseBody
    @GetMapping(value = DOSSIER_REST_PATH + DOSSIER_ID_PATH_PARAM, produces = MediaType.APPLICATION_JSON_VALUE)
    @Operation(summary = "Gets an existing dossier.", description = "None")
    @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK"), @ApiResponse(responseCode = "404", description = "Not found")})
    Dossier getDossier(@PathVariable(DOSSIER_ID_PARAM) String dossierId,
                       @RequestParam(name = INCLUDE_ARCHIVED_PARAM, defaultValue = "false", required = false) boolean includeArchived,
                       @RequestParam(name = INCLUDE_DELETED_PARAM, defaultValue = "false", required = false) boolean includeDeleted);


    @ResponseStatus(value = HttpStatus.OK)
    @ResponseBody
    @GetMapping(value = DOSSIER_REST_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
    @Operation(summary = "Gets all existing dossiers.", description = "None")
    @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
    List<Dossier> getDossiers(@RequestParam(name = INCLUDE_ARCHIVED_PARAM, defaultValue = "false", required = false) boolean includeArchived,
                              @RequestParam(name = INCLUDE_DELETED_PARAM, defaultValue = "false", required = false) boolean includeDeleted);


    @ResponseStatus(value = HttpStatus.OK)
    @ResponseBody
    @GetMapping(value = DOSSIER_REST_PATH + DOSSIER_TEMPLATE_PATH + DOSSIER_TEMPLATE_ID_PATH_PARAM, produces = MediaType.APPLICATION_JSON_VALUE)
    @Operation(summary = "Gets all existing dossiers for the given dossier template id.", description = "None")
    @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
    List<Dossier> getDossiersForDossierTemplate(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId,
                                                @RequestParam(name = INCLUDE_ARCHIVED_PARAM, defaultValue = "false", required = false) boolean includeArchived,
                                                @RequestParam(name = INCLUDE_DELETED_PARAM, defaultValue = "false", required = false) boolean includeDeleted);


    @ResponseStatus(value = HttpStatus.OK)
    @ResponseBody
    @GetMapping(value = DELETED_DOSSIERS_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
    @Operation(summary = "Gets all deleted dossiers.", description = "None")
    @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
    List<Dossier> getSoftDeletedDossiers();


    @ResponseStatus(value = HttpStatus.OK)
    @ResponseBody
    @GetMapping(value = ARCHIVE_DOSSIERS_PATH, produces = MediaType.APPLICATION_JSON_VALUE)
    @Operation(summary = "Gets all archived dossiers.", description = "None")
    @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
    List<Dossier> getArchivedDossiers();


    @ResponseStatus(value = HttpStatus.OK)
    @ResponseBody
    @GetMapping(value = ARCHIVE_DOSSIERS_PATH + DOSSIER_TEMPLATE_PATH + DOSSIER_TEMPLATE_ID_PATH_PARAM, produces = MediaType.APPLICATION_JSON_VALUE)
    @Operation(summary = "Gets all archived dossiers for the given dossier template id.", description = "None")
    @ApiResponses(value = {@ApiResponse(responseCode = "200", description = "OK")})
    List<Dossier> getArchivedDossiersForDossierTemplate(@PathVariable(DOSSIER_TEMPLATE_ID_PARAM) String dossierTemplateId);


    @ResponseStatus(value = HttpStatus.NO_CONTENT)
    @PostMapping(value = ARCHIVE_DOSSIERS_PATH + ARCHIVE_PATH)
    @Operation(summary = "Archives an existing dossier.", description = "None")
    @ApiResponses(value = {@ApiResponse(responseCode = "204", description = "Successfully archived the dossier."), @ApiResponse(responseCode = "400", description = "Incorrect dossier ID entered to archive dossier."), @ApiResponse(responseCode = "403", description = "Forbidden operation while archiving."), @ApiResponse(responseCode = "404", description = "Dossier not found")})
    void archiveDossiers(@RequestBody Set<String> dossierIds);


    @ResponseStatus(value = HttpStatus.NO_CONTENT)
    @PostMapping(value = ARCHIVE_DOSSIERS_PATH + UNARCHIVE_PATH, consumes = MediaType.APPLICATION_JSON_VALUE)
    @Operation(summary = "Restores archived dossiers.", description = "None")
    @ApiResponses(value = {@ApiResponse(responseCode = "204", description = "Successfully restored the dossiers."), @ApiResponse(responseCode = "400", description = "Incorrect dossier ID entered to restore dossier."), @ApiResponse(responseCode = "403", description = "Forbidden operation while restoring."), @ApiResponse(responseCode = "404", description = "Dossier not found"), @ApiResponse(responseCode = "409", description = "Conflict occurred while restoring.")})
    void unarchiveDossiers(@RequestBody Set<String> dossierIds);


    @ResponseStatus(value = HttpStatus.NO_CONTENT)
    @DeleteMapping(value = DELETED_DOSSIERS_PATH + HARD_DELETE_PATH)
    @Operation(summary = "Hard deletes existing dossiers.", description = "None")
    @ApiResponses(value = {@ApiResponse(responseCode = "204", description = "Successfully hard deleted the dossier."), @ApiResponse(responseCode = "404", description = "Not found")})
    void hardDeleteDossiers(@RequestParam(DOSSIER_ID_PARAM) Set<String> dossierIds);


    @ResponseBody
    @PostMapping(value = DELETED_DOSSIERS_PATH + UNDELETE_PATH, consumes = MediaType.APPLICATION_JSON_VALUE)
    @Operation(summary = "Restores dossiers.", description = "None")
    @ApiResponses(value = {@ApiResponse(responseCode = "201", description = "Successfully restored the dossiers."), @ApiResponse(responseCode = "400", description = "Incorrect dossier ID entered to restore dossier."), @ApiResponse(responseCode = "403", description = "Forbidden operation while restoring."), @ApiResponse(responseCode = "409", description = "Conflict occurred while restoring.")})
    void undeleteDossiers(@RequestBody Set<String> dossierIds);

}
