package cloud.nstart.terravault.ordinis.restapi.web;

import cloud.nstart.terravault.ordinis.restapi.dto.draft.DraftResponse;
import cloud.nstart.terravault.ordinis.restapi.dto.draft.SubmitDraftRequest;
import cloud.nstart.terravault.ordinis.restapi.service.draft.DraftService;
import jakarta.validation.Valid;
import org.springframework.data.domain.PageRequest;
import org.springframework.http.HttpStatus;
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.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * Approval workflow draft endpoints — Phase 0 skeleton.
 *
 * <p>Submit + list per dict + global queue + get by id.
 * Approve / reject / withdraw / update — Phase 1.
 *
 * <p>Дизайн doc: ~/.gstack/projects/claude/zimin-main-design-approval-workflow-v2-20260507-121632.md
 */
@RestController
public class DraftController {

  private final DraftService draftService;

  public DraftController(DraftService draftService) {
    this.draftService = draftService;
  }

  /**
   * Maker submits новый proposal. Returns 201 Created с full draft response.
   * Если pending draft на этот business_key уже есть → 409 draft_already_pending.
   */
  @PostMapping("/api/v1/dictionaries/{name}/records/drafts")
  @ResponseStatus(HttpStatus.CREATED)
  public DraftResponse submit(
      @PathVariable String name,
      @Valid @RequestBody SubmitDraftRequest req) {
    return DraftResponse.from(draftService.submit(name, req));
  }

  /** Per-dictionary pending list. */
  @RequestMapping(method = org.springframework.web.bind.annotation.RequestMethod.GET,
      value = "/api/v1/dictionaries/{name}/records/drafts")
  public List<DraftResponse> listByDict(@PathVariable String name) {
    return draftService.listPendingByDictionary(name).stream()
        .map(DraftResponse::from)
        .toList();
  }

  /** Single draft по id (для drilling в reviewer queue). */
  @GetMapping("/api/v1/drafts/{id}")
  public DraftResponse getById(@PathVariable UUID id) {
    return DraftResponse.from(draftService.findById(id));
  }

  /**
   * Global reviewer queue (D3=A pool model). Все pending drafts отсортированы
   * by submitted_at ASC (oldest first — fairness).
   */
  @GetMapping("/api/v1/admin/reviews/pending")
  public Map<String, Object> globalQueue(
      @RequestParam(defaultValue = "0") int page,
      @RequestParam(defaultValue = "50") int size) {
    var pg = draftService.listPendingGlobal(PageRequest.of(page, Math.min(size, 200)));
    return Map.of(
        "items", pg.getContent().stream().map(DraftResponse::from).toList(),
        "page", pg.getNumber(),
        "size", pg.getSize(),
        "totalElements", pg.getTotalElements(),
        "totalPages", pg.getTotalPages());
  }

  /**
   * Approve pending draft → COPY → live + outbox event. Reviewer = current
   * authenticated user (must != maker, D3 pool model with self-approve guard).
   */
  @PostMapping("/api/v1/drafts/{id}/approve")
  public DraftResponse approve(
      @PathVariable UUID id,
      @RequestParam(required = false) String comment) {
    return DraftResponse.from(draftService.approve(id, comment));
  }

  /**
   * Reject pending draft (D4 soft-archive). Reviewer must provide non-blank
   * reason — compliance + maker видит почему отклонено.
   */
  @PostMapping("/api/v1/drafts/{id}/reject")
  public DraftResponse reject(
      @PathVariable UUID id,
      @RequestParam String comment) {
    return DraftResponse.from(draftService.reject(id, comment));
  }

  /**
   * Maker отзывает свой pending draft (передумал). Только сам maker может
   * — reviewer'ам это недоступно.
   */
  @DeleteMapping("/api/v1/drafts/{id}")
  public DraftResponse withdraw(@PathVariable UUID id) {
    return DraftResponse.from(draftService.withdraw(id));
  }

  /**
   * Maker self-tracking: "что я отправил". Возвращает все статусы (PENDING /
   * APPROVED / REJECTED / WITHDRAWN) для current authenticated user, sorted
   * submitted_at DESC. Phase 4 UX: makers видят свои submissions без access
   * к /reviews (доступен только pool reviewer'ам).
   */
  @GetMapping("/api/v1/drafts/me")
  public Map<String, Object> myDrafts(
      @RequestParam(defaultValue = "0") int page,
      @RequestParam(defaultValue = "50") int size) {
    String makerId = currentUserId();
    var pg = draftService.listByMaker(makerId, PageRequest.of(page, Math.min(size, 200)));
    return Map.of(
        "items", pg.getContent().stream().map(DraftResponse::from).toList(),
        "page", pg.getNumber(),
        "size", pg.getSize(),
        "totalElements", pg.getTotalElements(),
        "totalPages", pg.getTotalPages());
  }

  /** Resolve current user from JWT subject. Fallback "anonymous" если auth off. */
  private static String currentUserId() {
    var auth = org.springframework.security.core.context.SecurityContextHolder
        .getContext().getAuthentication();
    if (auth == null || !auth.isAuthenticated()) return "anonymous";
    return auth.getName();
  }
}
