package de.nowchess.backcore.resource

import de.nowchess.backcore.dto.*
import de.nowchess.backcore.game.{GameMapper, GameService}
import jakarta.enterprise.context.ApplicationScoped
import jakarta.inject.Inject
import jakarta.ws.rs.*
import jakarta.ws.rs.core.{MediaType, Response}

@Path("/api/board/game")
@Produces(Array(MediaType.APPLICATION_JSON))
@ApplicationScoped
class GameResource @Inject() (service: GameService):

  @POST
  @Consumes(Array(MediaType.APPLICATION_JSON))
  def createGame(req: CreateGameRequest): Response =
    val snapshot = service.reset(Option(req).getOrElse(CreateGameRequest()))
    Response.status(201).entity(GameMapper.toGameFull(snapshot)).build()

  @GET
  @Path("/{gameId}")
  def getGame(@PathParam("gameId") gameId: String): Response =
    if !service.isKnownId(gameId) then
      Response
        .status(404)
        .entity(ApiErrorResponse("GAME_NOT_FOUND", s"Game $gameId not found"))
        .build()
    else Response.ok(GameMapper.toGameFull(service.getSnapshot)).build()

  @GET
  @Path("/{gameId}/stream")
  @Produces(Array("application/x-ndjson"))
  def streamGame(@PathParam("gameId") gameId: String): Response =
    if !service.isKnownId(gameId) then
      Response
        .status(404)
        .`type`(MediaType.APPLICATION_JSON)
        .entity(ApiErrorResponse("GAME_NOT_FOUND", s"Game $gameId not found"))
        .build()
    else
      val event = s"""{"type":"gameFull","game":${GameMapper.toGameFullJson(service.getSnapshot)}}"""
      Response.ok(event + "\n").build()

  @POST
  @Path("/{gameId}/resign")
  def resignGame(@PathParam("gameId") gameId: String): Response =
    if !service.isKnownId(gameId) then
      Response.status(404).entity(ApiErrorResponse("GAME_NOT_FOUND", s"Game $gameId not found")).build()
    else
      service.resign() match
        case Right(_)  => Response.ok(OkResponse()).build()
        case Left(err) => Response.status(400).entity(ApiErrorResponse("RESIGN_ERROR", err)).build()

  @POST
  @Path("/{gameId}/draw/{action}")
  def drawAction(
      @PathParam("gameId") gameId: String,
      @PathParam("action") action: String,
  ): Response =
    if !service.isKnownId(gameId) then
      Response.status(404).entity(ApiErrorResponse("GAME_NOT_FOUND", s"Game $gameId not found")).build()
    else
      service.drawAction(action) match
        case Right(_)  => Response.ok(OkResponse()).build()
        case Left(err) => Response.status(400).entity(ApiErrorResponse("DRAW_ERROR", err)).build()

  @GET
  @Path("/{gameId}/export/fen")
  @Produces(Array(MediaType.TEXT_PLAIN))
  def exportFen(@PathParam("gameId") gameId: String): Response =
    if !service.isKnownId(gameId) then
      Response
        .status(404)
        .`type`(MediaType.APPLICATION_JSON)
        .entity(ApiErrorResponse("GAME_NOT_FOUND", s"Game $gameId not found"))
        .build()
    else Response.ok(service.exportFen()).build()

  @GET
  @Path("/{gameId}/export/pgn")
  @Produces(Array("application/x-chess-pgn"))
  def exportPgn(@PathParam("gameId") gameId: String): Response =
    if !service.isKnownId(gameId) then
      Response
        .status(404)
        .`type`(MediaType.APPLICATION_JSON)
        .entity(ApiErrorResponse("GAME_NOT_FOUND", s"Game $gameId not found"))
        .build()
    else Response.ok(service.exportPgn()).build()
