package com.pandoli365.bibimbap.controller;

import com.pandoli365.bibimbap.data.JamData;
import com.pandoli365.bibimbap.data.JamJudgeData;
import com.pandoli365.bibimbap.data.UserData;
import com.pandoli365.bibimbap.mapper.JamJudgesMapper;
import com.pandoli365.bibimbap.mapper.JamsMapper;
import com.pandoli365.bibimbap.mapper.UsersMapper;
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 org.springframework.dao.DuplicateKeyException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.transaction.annotation.Transactional;
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.RequestParam;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Controller
public class JamJudgeAdminController {

    private final JamsMapper jamsMapper;
    private final UsersMapper usersMapper;
    private final JamJudgesMapper jamJudgesMapper;
    private final PermissionGate gate;

    public JamJudgeAdminController(JamsMapper jamsMapper,
                                   UsersMapper usersMapper,
                                   JamJudgesMapper jamJudgesMapper,
                                   PermissionGate gate) {
        this.jamsMapper = jamsMapper;
        this.usersMapper = usersMapper;
        this.jamJudgesMapper = jamJudgesMapper;
        this.gate = gate;
    }

    @PostMapping("/admin/jams/{jamId}/judges")
    @Transactional
    public ResponseEntity<Map<String, Object>> assign(
            @PathVariable("jamId") long jamId,
            @RequestParam("userId") long userId,
            HttpServletRequest request,
            HttpSession session) {
        ResponseEntity<Map<String, Object>> denied = requireJamManage(session);
        if (denied != null) {
            return denied;
        }
        if (!CsrfTokens.isValid(request)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).body(CsrfTokens.errorBody());
        }
        JamData jam = jamsMapper.getById(jamId);
        if (jam == null) {
            return response(HttpStatus.NOT_FOUND, "게임잼을 찾을 수 없습니다.");
        }
        UserData target = usersMapper.getUser(userId);
        if (target == null) {
            return response(HttpStatus.NOT_FOUND, "대상 사용자를 찾을 수 없습니다.");
        }
        if (jamJudgesMapper.exists(jamId, userId)) {
            return response(HttpStatus.CONFLICT, "이미 심사위원입니다.");
        }

        long actorId = sessionUserId(session);
        try {
            jamJudgesMapper.insert(jamId, userId, actorId);
        } catch (DuplicateKeyException e) {
            // ux_jam_judges_jam_user 경합 — exists 통과 후 동시 insert 시 409로 수렴
            return response(HttpStatus.CONFLICT, "이미 심사위원입니다.");
        }

        Map<String, Object> body = new LinkedHashMap<>();
        body.put("status", HttpStatus.OK.value());
        body.put("message", "심사위원을 지정했습니다.");
        body.put("jamId", jamId);
        body.put("userId", userId);
        return ResponseEntity.ok(body);
    }

    @PostMapping("/admin/jams/{jamId}/judges/{userId}/remove")
    @Transactional
    public ResponseEntity<Map<String, Object>> remove(
            @PathVariable("jamId") long jamId,
            @PathVariable("userId") long userId,
            HttpServletRequest request,
            HttpSession session) {
        ResponseEntity<Map<String, Object>> denied = requireJamManage(session);
        if (denied != null) {
            return denied;
        }
        if (!CsrfTokens.isValid(request)) {
            return ResponseEntity.status(HttpStatus.FORBIDDEN).body(CsrfTokens.errorBody());
        }

        int affected = jamJudgesMapper.delete(jamId, userId);
        if (affected == 0) {
            return response(HttpStatus.NOT_FOUND, "지정된 심사위원이 아닙니다.");
        }

        Map<String, Object> body = new LinkedHashMap<>();
        body.put("status", HttpStatus.OK.value());
        body.put("message", "심사위원을 해제했습니다.");
        body.put("jamId", jamId);
        body.put("userId", userId);
        body.put("removed", true);
        return ResponseEntity.ok(body);
    }

    @GetMapping("/admin/jams/{jamId}/judges")
    public ResponseEntity<Map<String, Object>> list(
            @PathVariable("jamId") long jamId,
            HttpSession session) {
        ResponseEntity<Map<String, Object>> denied = requireJamManage(session);
        if (denied != null) {
            return denied;
        }

        List<JamJudgeData> judges = jamJudgesMapper.listByJam(jamId);
        List<Map<String, Object>> items = new ArrayList<>(judges.size());
        for (JamJudgeData judge : judges) {
            Map<String, Object> item = new LinkedHashMap<>();
            item.put("userId", judge.getUserId());
            item.put("displayName", judge.getDisplayName());
            item.put("assignedBy", judge.getAssignedBy());
            item.put("createdAt", judge.getCreatedAt());
            items.add(item);
        }

        Map<String, Object> body = new LinkedHashMap<>();
        body.put("status", HttpStatus.OK.value());
        body.put("judges", items);
        return ResponseEntity.ok(body);
    }

    private ResponseEntity<Map<String, Object>> requireJamManage(HttpSession session) {
        if (!gate.isAuthenticated(session)) {
            return response(HttpStatus.UNAUTHORIZED, "로그인이 필요합니다.");
        }
        if (!gate.has(session, PermissionKeys.GAME_JAM_MANAGE.name())) {
            return response(HttpStatus.FORBIDDEN, "권한이 없습니다.");
        }
        return null;
    }

    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;
    }
}
