package com.pandoli365.bibimbap.controller;

import com.pandoli365.bibimbap.badge.BadgeService;
import com.pandoli365.bibimbap.badge.BadgeService.GrantResult;
import com.pandoli365.bibimbap.badge.BadgeService.RevokeResult;
import com.pandoli365.bibimbap.security.CsrfTokens;
import com.pandoli365.bibimbap.security.PermissionGate;
import com.pandoli365.bibimbap.security.PermissionKeys;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * /manage/** 는 인터셉터 미등록 경로이므로 진입부에서 CSRF·PermissionGate 게이트를 직접 호출한다.
 */
@Controller
public class BadgeManageController {

    private final BadgeService badgeService;
    private final PermissionGate permissionGate;

    public BadgeManageController(BadgeService badgeService, PermissionGate permissionGate) {
        this.badgeService = badgeService;
        this.permissionGate = permissionGate;
    }

    @PostMapping("/manage/users/{userId}/badges/{badgeKey}/grant")
    @ResponseBody
    public ResponseEntity<Map<String, Object>> grant(
            @PathVariable("userId") long userId,
            @PathVariable("badgeKey") String badgeKey,
            HttpServletRequest request,
            HttpSession session) {
        if (!CsrfTokens.isValid(request)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).body(CsrfTokens.errorBody());
        }
        if (!permissionGate.isAuthenticated(session)) {
            return response(HttpStatus.UNAUTHORIZED, "로그인이 필요합니다.");
        }
        if (!permissionGate.has(session, PermissionKeys.BADGE_MANAGE.name())) {
            return response(HttpStatus.FORBIDDEN, "권한이 없습니다.");
        }
        Long actorId = sessionUserId(session);
        if (actorId == null) {
            return response(HttpStatus.UNAUTHORIZED, "로그인이 필요합니다.");
        }

        GrantResult r = badgeService.grantManual(userId, badgeKey, actorId);
        switch (r) {
            case INVALID_BADGE:
                return response(HttpStatus.NOT_FOUND, "존재하지 않는 배지입니다.");
            case USER_NOT_FOUND:
                return response(HttpStatus.NOT_FOUND, "대상 사용자를 찾을 수 없습니다.");
            case ALREADY_ACTIVE:
                return response(HttpStatus.CONFLICT, "이미 보유한 배지입니다.");
            case GRANTED:
            default:
                Map<String, Object> body = new LinkedHashMap<>();
                body.put("status", 200);
                body.put("message", "배지를 부여했습니다.");
                body.put("userId", userId);
                body.put("badgeKey", badgeKey);
                body.put("awarded", true);
                return ResponseEntity.ok(body);
        }
    }

    @PostMapping("/manage/users/{userId}/badges/{badgeKey}/revoke")
    @ResponseBody
    public ResponseEntity<Map<String, Object>> revoke(
            @PathVariable("userId") long userId,
            @PathVariable("badgeKey") String badgeKey,
            @RequestParam(name = "reason", required = false) String reason,
            HttpServletRequest request,
            HttpSession session) {
        if (!CsrfTokens.isValid(request)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).body(CsrfTokens.errorBody());
        }
        if (!permissionGate.isAuthenticated(session)) {
            return response(HttpStatus.UNAUTHORIZED, "로그인이 필요합니다.");
        }
        if (!permissionGate.has(session, PermissionKeys.BADGE_MANAGE.name())) {
            return response(HttpStatus.FORBIDDEN, "권한이 없습니다.");
        }
        String trimmedReason = (reason == null) ? null : reason.trim();
        if (trimmedReason == null || trimmedReason.isBlank()) {
            return response(HttpStatus.BAD_REQUEST, "회수 사유를 입력해 주세요.");
        }

        RevokeResult r = badgeService.revokeManual(userId, badgeKey, trimmedReason);
        switch (r) {
            case INVALID_BADGE:
                return response(HttpStatus.NOT_FOUND, "존재하지 않는 배지입니다.");
            case NOT_ACTIVE:
                return response(HttpStatus.NOT_FOUND, "회수할 활성 배지가 없습니다.");
            case REVOKED:
            default:
                Map<String, Object> body = new LinkedHashMap<>();
                body.put("status", 200);
                body.put("message", "배지를 회수했습니다.");
                body.put("userId", userId);
                body.put("badgeKey", badgeKey);
                body.put("revoked", true);
                return ResponseEntity.ok(body);
        }
    }

    private ResponseEntity<Map<String, Object>> response(HttpStatus status, String message) {
        Map<String, Object> body = new LinkedHashMap<>();
        body.put("status", status.value());
        body.put("message", message);
        return ResponseEntity.status(status).body(body);
    }

    private Long sessionUserId(HttpSession session) {
        if (session == null) {
            return null;
        }
        Object userId = session.getAttribute("userId");
        if (userId instanceof Number number) {
            return number.longValue();
        }
        if (userId instanceof String text) {
            try {
                return Long.parseLong(text);
            } catch (NumberFormatException e) {
                return null;
            }
        }
        return null;
    }
}
