package com.zioinfo.kintex.hallassign;

import com.zioinfo.kintex.auth.EventAccessGuard;
import com.zioinfo.kintex.auth.KintexPrincipal;
import com.zioinfo.kintex.common.ApiResponse;
import com.zioinfo.kintex.common.ApiResponse.ApiError;
import com.zioinfo.kintex.common.audit.Audited;
import com.zioinfo.kintex.common.error.ApiException;
import com.zioinfo.kintex.common.error.ErrorCode;
import com.zioinfo.kintex.hallassign.dto.AssignmentRequest;
import com.zioinfo.kintex.hallassign.dto.ConflictDto;
import com.zioinfo.kintex.hallassign.dto.HallAssignmentDto;
import com.zioinfo.kintex.hallassign.dto.HallDto;
import com.zioinfo.kintex.hallassign.dto.QuoteRequest;
import com.zioinfo.kintex.hallassign.dto.QuoteResult;
import jakarta.validation.Valid;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
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;

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

/**
 * M1 홀 배정·자동 견적 API (SCR /halls).
 * <ul>
 *   <li>조회(홀·배정·충돌·견적): 로그인 필수.</li>
 *   <li>배정 변경(생성·해제): 홀매니저(킨텍스 내부)만 + {@link Audited}.</li>
 * </ul>
 * 충돌 시 POST 배정은 409 + 충돌 행사 목록(data)을 반환한다(계약).
 */
@RestController
@RequestMapping("/api/halls")
public class HallAssignController {

    private final HallAssignService service;
    private final EventAccessGuard guard;

    public HallAssignController(HallAssignService service, EventAccessGuard guard) {
        this.service = service;
        this.guard = guard;
    }

    /** GET /api/halls — 홀 마스터 전체(배정 보드 행·견적 근거). */
    @GetMapping
    public ApiResponse<List<HallDto>> halls(@AuthenticationPrincipal KintexPrincipal principal) {
        guard.require(principal);
        return ApiResponse.ok(service.halls());
    }

    /** GET /api/halls/assignments?from=&to=&eventId= — 배정 보드 목록(기간 겹침). 홀매니저 전용. */
    @GetMapping("/assignments")
    public ApiResponse<List<HallAssignmentDto>> assignments(@AuthenticationPrincipal KintexPrincipal principal,
                                                            @RequestParam(required = false) String from,
                                                            @RequestParam(required = false) String to,
                                                            @RequestParam(required = false) String eventId) {
        requireHallManager(principal);
        return ApiResponse.ok(service.assignments(from, to, eventId));
    }

    /** GET /api/halls/conflicts?hallId=&from=&to=&excludeEventId= — 홀·기간 충돌 사전검사(200). 홀매니저 전용. */
    @GetMapping("/conflicts")
    public ApiResponse<List<ConflictDto>> conflicts(@AuthenticationPrincipal KintexPrincipal principal,
                                                    @RequestParam String hallId,
                                                    @RequestParam String from,
                                                    @RequestParam String to,
                                                    @RequestParam(required = false) String excludeEventId) {
        requireHallManager(principal);
        return ApiResponse.ok(service.conflicts(hallId, from, to, excludeEventId));
    }

    /**
     * POST /api/halls/assignments — 홀 배정 생성. 홀매니저 전용 + 감사.
     * 겹침 충돌 시 409 + {@code { conflicts: [...] }} 반환(계약).
     */
    @PostMapping("/assignments")
    @Audited(action = "HALL_ASSIGN_CREATE", targetType = "hall_assignment")
    public ResponseEntity<ApiResponse<Object>> assign(@AuthenticationPrincipal KintexPrincipal principal,
                                                      @Valid @RequestBody AssignmentRequest req) {
        requireHallManager(principal);
        try {
            HallAssignmentDto created = service.assign(req);
            return ResponseEntity.ok(ApiResponse.ok(created));
        } catch (HallAssignConflictException ex) {
            Object body = Map.of("conflicts", ex.conflicts());
            return ResponseEntity.status(HttpStatus.CONFLICT)
                    .body(new ApiResponse<>(false, body, new ApiError(ErrorCode.CONFLICT.name(), ex.getMessage())));
        }
    }

    /** DELETE /api/halls/assignments/{id} — 홀 배정 해제. 홀매니저 전용 + 감사. */
    @DeleteMapping("/assignments/{id}")
    @Audited(action = "HALL_ASSIGN_RELEASE", targetType = "hall_assignment")
    public ApiResponse<Void> release(@AuthenticationPrincipal KintexPrincipal principal,
                                     @PathVariable String id) {
        requireHallManager(principal);
        service.release(id);
        return ApiResponse.ok(null);
    }

    /** POST /api/halls/quote — 자동 견적(요율 룰셋 rates-v1.0). 로그인 필수(참가/주최자 셀프 견적 허용). */
    @PostMapping("/quote")
    public ApiResponse<QuoteResult> quote(@AuthenticationPrincipal KintexPrincipal principal,
                                          @Valid @RequestBody QuoteRequest req) {
        guard.require(principal);
        return ApiResponse.ok(service.quote(req));
    }

    /** 홀 배정 변경 권한 — 킨텍스 내부 홀매니저만(§2 최종 배정 확정은 킨텍스 내부 의사결정). */
    private void requireHallManager(KintexPrincipal principal) {
        guard.require(principal);
        if (!principal.hallManager()) {
            throw new ApiException(ErrorCode.FORBIDDEN, "홀 배정은 킨텍스 홀매니저만 변경할 수 있습니다.");
        }
    }
}
