package com.securityc4po.api.pentest

import com.securityc4po.api.configuration.BC_BAD_CAST_TO_ABSTRACT_COLLECTION
import com.securityc4po.api.extensions.getLoggerFor
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings
import com.securityc4po.api.ResponseBody
import org.springframework.http.ResponseEntity
import org.springframework.http.ResponseEntity.noContent
import org.springframework.web.bind.annotation.*
import reactor.core.publisher.Mono

@RestController
@RequestMapping("/pentests")
@CrossOrigin(
    origins = [],
    allowCredentials = "false",
    allowedHeaders = ["*"],
    methods = [RequestMethod.GET, RequestMethod.DELETE, RequestMethod.POST, RequestMethod.PATCH]
)
@SuppressFBWarnings(BC_BAD_CAST_TO_ABSTRACT_COLLECTION)
class PentestController(
    private val pentestService: PentestService,
    private val pentestReportService: PentestReportService
) {

    var logger = getLoggerFor<PentestController>()

    @GetMapping
    fun getPentestsByProjectIdAndCategory(
        @RequestParam("projectId") projectId: String,
        @RequestParam("category") category: String
    ): Mono<ResponseEntity<List<ResponseBody>>> {
        return pentestService.getPentestsForCategory(projectId, PentestCategory.valueOf(category)).map { pentestList ->
            pentestList.map {
                it.toPentestResponseBody()
            }
        }.map {
            if (it.isEmpty()) noContent().build()
            else ResponseEntity.ok(it)
        }
    }

    @GetMapping("/{pentestId}")
    fun getCompletedPentestById(
        @PathVariable(value = "pentestId") pentestId: String
    ): Mono<ResponseEntity<ResponseBody>> {
        return pentestReportService.getCompletedPentest(pentestId).map {
            ResponseEntity.ok(it.toCompletedPentestResponseBody())
        }
    }

    @PostMapping("/{projectId}")
    fun savePentest(
        @PathVariable(value = "projectId") projectId: String,
        @RequestBody body: PentestRequestBody
    ): Mono<ResponseEntity<ResponseBody>> {
        return this.pentestService.savePentest(projectId, body).map {
            ResponseEntity.accepted().body(it.toPentestResponseBody())
        }
    }

    @PatchMapping("/{pentestId}")
    fun updatePentest(
        @PathVariable(value = "pentestId") pentestId: String,
        @RequestBody body: PentestRequestBody
    ): Mono<ResponseEntity<ResponseBody>> {
        return this.pentestService.updatePentest(pentestId, body).map {
            ResponseEntity.accepted().body(it.toPentestResponseBody())
        }
    }

    /**
     * Disables the [Pentest]
     *
     * @param pentestId: Id of the pentest
     * @return The disabled [Pentest]
     */
    @PostMapping("/{projectId}/{pentestId}/disable")
    fun disablePentestObjective(
        @PathVariable(value = "projectId") projectId: String,
        @PathVariable(value = "pentestId") pentestId: String
    ): Mono<ResponseEntity<ResponseBody>> {
        return this.pentestService.enableOrDisableObjectiveByPentestId(projectId, pentestId, false).map {
            ResponseEntity.accepted().body(it.toPentestResponseBody())
        }
    }

    /**
     * Enables the [Pentest]
     *
     * @param pentestId: Id of the pentest
     * @return The enabled [Pentest]
     */
    @PostMapping("/{projectId}/{pentestId}/enable")
    fun enablePentestObjective(
        @PathVariable(value = "projectId") projectId: String,
        @PathVariable(value = "pentestId") pentestId: String
    ): Mono<ResponseEntity<ResponseBody>> {
        return this.pentestService.enableOrDisableObjectiveByPentestId(projectId, pentestId, true).map {
            ResponseEntity.accepted().body(it.toPentestResponseBody())
        }
    }
}