package com.securityc4po.api.pentest.finding

import com.securityc4po.api.pentest.PentestService
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
import reactor.kotlin.core.publisher.switchIfEmpty

@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 FindingController(private val pentestService: PentestService, private val findingService: FindingService) {

    var logger = getLoggerFor<FindingController>()

    @GetMapping("/{pentestId}/findings")
    fun getFindings(@PathVariable(value = "pentestId") pentestId: String): Mono<ResponseEntity<List<ResponseBody>>> {
        return this.pentestService.getFindingIdsByPentestId(pentestId).flatMap { findingIds: List<String> ->
            this.findingService.getFindingsByIds(findingIds).map { findingList ->
                findingList.map { it.toFindingResponseBody() }
            }
        }.map {
            if (it.isEmpty()) noContent().build()
            else ResponseEntity.ok(it)
        }
    }

    @GetMapping("/{findingId}/finding")
    fun getFinding(@PathVariable(value = "findingId") findingId: String):Mono<ResponseEntity<ResponseBody>> {
        return this.findingService.getFindingById(findingId).map {
            ResponseEntity.ok().body(it.toFindingResponseBody())
        }
    }

    @PostMapping("/{pentestId}/finding")
    fun saveFinding(
        @PathVariable(value = "pentestId") pentestId: String,
        @RequestBody body: FindingRequestBody
    ): Mono<ResponseEntity<ResponseBody>> {
        return this.findingService.saveFinding(pentestId, body).map {
            ResponseEntity.accepted().body(it.toFindingResponseBody())
        }
    }

    @PatchMapping("/{findingId}/finding")
    fun updateFinding(
        @PathVariable(value = "findingId") findingId: String,
        @RequestBody body: FindingRequestBody
    ): Mono<ResponseEntity<ResponseBody>> {
        return this.findingService.updateFinding(findingId, body).map {
            ResponseEntity.accepted().body(it.toFindingResponseBody())
        }
    }

    @DeleteMapping("/{pentestId}/finding/{findingId}")
    fun deleteFinding(
        @PathVariable(value = "pentestId") pentestId: String,
        @PathVariable(value = "findingId") findingId: String
    ): Mono<ResponseEntity<ResponseBody>> {
        // ToDo: Add remove finding from comment as well
        return this.findingService.deleteFindingByPentestAndFindingId(pentestId, findingId).map {
            ResponseEntity.ok().body(it.toFindingDeleteResponseBody())
        }.switchIfEmpty {
            Mono.just(noContent().build<ResponseBody>())
        }
    }
}