package com.kamco.cd.kamcoback.zoo;

import com.kamco.cd.kamcoback.config.api.ApiResponseDto;
import com.kamco.cd.kamcoback.zoo.dto.ZooDto;
import com.kamco.cd.kamcoback.zoo.dto.ZooDto.Detail;
import com.kamco.cd.kamcoback.zoo.service.ZooService;
import io.swagger.v3.oas.annotations.Hidden;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
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.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@Hidden
@Tag(name = "Zoo", description = "동물원 관리 API")
@RequiredArgsConstructor
@RestController
@RequestMapping({"/api/zoos", "/v1/api/zoos"})
public class ZooApiController {

  private final ZooService zooService;

  /**
   * 동물원 생성
   *
   * @param req 동물원 생성 요청
   * @return 생성된 동물원 정보 (동물 개수 포함)
   */
  @Operation(summary = "동물원 생성", description = "새로운 동물원 정보를 등록합니다.")
  @ApiResponses(
      value = {
        @ApiResponse(
            responseCode = "201",
            description = "동물원 생성 성공",
            content =
                @Content(
                    mediaType = "application/json",
                    schema = @Schema(implementation = ZooDto.Detail.class))),
        @ApiResponse(responseCode = "400", description = "잘못된 요청 데이터", content = @Content),
        @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
      })
  @PostMapping
  public ApiResponseDto<Detail> createZoo(
      @io.swagger.v3.oas.annotations.parameters.RequestBody(
              description = "동물원 생성 요청 정보",
              required = true,
              content =
                  @Content(
                      mediaType = "application/json",
                      schema = @Schema(implementation = ZooDto.AddReq.class)))
          @RequestBody
          ZooDto.AddReq req) {
    ZooDto.Detail created = zooService.createZoo(req);
    return ApiResponseDto.createOK(created);
  }

  /**
   * UUID로 동물원 조회
   *
   * @param uuid 동물원 UUID
   * @return 동물원 정보 (현재 동물 개수 포함)
   */
  @Operation(summary = "동물원 단건 조회", description = "UUID로 특정 동물원의 상세 정보를 조회합니다.")
  @ApiResponses(
      value = {
        @ApiResponse(
            responseCode = "200",
            description = "조회 성공",
            content =
                @Content(
                    mediaType = "application/json",
                    schema = @Schema(implementation = ZooDto.Detail.class))),
        @ApiResponse(responseCode = "404", description = "동물원을 찾을 수 없음", content = @Content),
        @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
      })
  @GetMapping("/{uuid}")
  public ApiResponseDto<ZooDto.Detail> getZoo(
      @Parameter(
              description = "조회할 동물원의 UUID",
              required = true,
              example = "550e8400-e29b-41d4-a716-446655440000")
          @PathVariable
          String uuid) {
    Long id = zooService.getZooByUuid(uuid);
    ZooDto.Detail zoo = zooService.getZoo(id);
    return ApiResponseDto.ok(zoo);
  }

  /**
   * UUID로 동물원 삭제 (논리 삭제)
   *
   * @param uuid 동물원 UUID
   * @return 삭제 성공 메시지
   */
  @Operation(summary = "동물원 삭제", description = "UUID로 특정 동물원을 삭제합니다 (논리 삭제).")
  @ApiResponses(
      value = {
        @ApiResponse(responseCode = "204", description = "삭제 성공", content = @Content),
        @ApiResponse(responseCode = "404", description = "동물원을 찾을 수 없음", content = @Content),
        @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
      })
  @DeleteMapping("/{uuid}")
  public ApiResponseDto<String> deleteZoo(
      @Parameter(
              description = "삭제할 동물원의 UUID",
              required = true,
              example = "550e8400-e29b-41d4-a716-446655440000")
          @PathVariable
          String uuid) {
    Long id = zooService.getZooByUuid(uuid);
    zooService.deleteZoo(id);
    return ApiResponseDto.deleteOk(uuid);
  }

  /**
   * 동물원 검색 (페이징)
   *
   * @param name 동물원 이름 (선택)
   * @param location 위치 (선택)
   * @param page 페이지 번호 (기본값: 0)
   * @param size 페이지 크기 (기본값: 20)
   * @param sort 정렬 조건 (예: "name,asc")
   * @return 페이징 처리된 동물원 목록 (각 동물원의 현재 동물 개수 포함)
   */
  @Operation(
      summary = "동물원 검색",
      description =
          "다양한 조건으로 동물원을 검색하고 페이징된 결과를 반환합니다. 모든 검색 조건은 선택적이며, 조건 없이 호출하면 전체 동물원 목록을 반환합니다.")
  @ApiResponses(
      value = {
        @ApiResponse(
            responseCode = "200",
            description = "검색 성공",
            content =
                @Content(
                    mediaType = "application/json",
                    schema = @Schema(implementation = Page.class))),
        @ApiResponse(responseCode = "400", description = "잘못된 검색 조건", content = @Content),
        @ApiResponse(responseCode = "500", description = "서버 오류", content = @Content)
      })
  @GetMapping
  public ApiResponseDto<Page<ZooDto.Detail>> searchZoos(
      @Parameter(description = "동물원 이름 (부분 일치 검색)", example = "서울동물원")
          @RequestParam(required = false)
          String name,
      @Parameter(description = "위치", example = "서울") @RequestParam(required = false)
          String location,
      @Parameter(description = "페이지 번호 (0부터 시작)", example = "0") @RequestParam(defaultValue = "0")
          int page,
      @Parameter(description = "페이지 크기", example = "20") @RequestParam(defaultValue = "20")
          int size,
      @Parameter(description = "정렬 조건 (형식: 필드명,방향)", example = "name,asc")
          @RequestParam(required = false)
          String sort) {
    ZooDto.SearchReq searchReq = new ZooDto.SearchReq(name, location, page, size, sort);
    Page<ZooDto.Detail> zoos = zooService.search(searchReq);
    return ApiResponseDto.ok(zoos);
  }
}
