package com.yimeng.okr.controller;

import com.yimeng.okr.dto.ApiResult;
import com.yimeng.okr.annotation.OperationLogAnnotation;
import com.yimeng.okr.dto.ScoringDto;
import com.yimeng.okr.entity.PerformanceScore;
import com.yimeng.okr.security.SecurityUtils;
import com.yimeng.okr.service.PerformanceService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

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

@RestController
@RequestMapping("/api/scores")
@RequiredArgsConstructor
public class PerformanceController {

    private final PerformanceService performanceService;

    // Self evaluation

    @PostMapping("/self")
    @OperationLogAnnotation(action = "SUBMIT_SELF_SCORE", entityType = "performance_score", sensitive = true)
    public ApiResult<PerformanceScore> submitSelf(@RequestBody Map<String, Object> body) {
        Long periodId = Long.valueOf(body.get("periodId").toString());
        Long userId = SecurityUtils.getCurrentUserId();
        Double okrScore = toDouble(body.get("okrScore"));
        Double kpiScore = toDouble(body.get("kpiScore"));
        Double bonus = toDouble(body.get("bonus"));
        Double penalty = toDouble(body.get("penalty"));
        String commentsJson = body.getOrDefault("commentsJson", "{}").toString();
        return ApiResult.success(
                performanceService.submitSelfScore(periodId, userId, okrScore, kpiScore, bonus, penalty, commentsJson));
    }

    // Superior scoring

    @PostMapping("/superior")
    @OperationLogAnnotation(action = "SUBMIT_SUPERIOR_SCORE", entityType = "performance_score", sensitive = true)
    public ApiResult<PerformanceScore> submitSuperior(@RequestBody Map<String, Object> body) {
        Long periodId = Long.valueOf(body.get("periodId").toString());
        Long targetUserId = Long.valueOf(body.get("userId").toString());
        Long evaluatorId = SecurityUtils.getCurrentUserId();
        Double okrScore = toDouble(body.get("okrScore"));
        Double kpiScore = toDouble(body.get("kpiScore"));
        Double bonus = toDouble(body.get("bonus"));
        Double penalty = toDouble(body.get("penalty"));
        String commentsJson = body.getOrDefault("commentsJson", "{}").toString();
        return ApiResult.success(
                performanceService.submitSuperiorScore(periodId, targetUserId, evaluatorId,
                        okrScore, kpiScore, bonus, penalty, commentsJson));
    }

    // Same-screen query (OKR + scores)

    @GetMapping("/page")
    @OperationLogAnnotation(action = "VIEW_SCORE_PAGE", entityType = "performance_score", sensitive = true)
    public ApiResult<ScoringDto> getScoringPage(@RequestParam Long periodId,
                                                 @RequestParam Long userId) {
        return ApiResult.success(performanceService.getScoringPage(periodId, userId, SecurityUtils.getCurrentUserId()));
    }

    @GetMapping("/my")
    @OperationLogAnnotation(action = "VIEW_MY_SCORE", entityType = "performance_score", sensitive = true)
    public ApiResult<ScoringDto> getMyResult(@RequestParam Long periodId) {
        return ApiResult.success(performanceService.getMyResult(periodId, SecurityUtils.getCurrentUserId()));
    }

    @PostMapping("/confirm")
    @OperationLogAnnotation(action = "CONFIRM_SCORE", entityType = "performance_score", sensitive = true)
    public ApiResult<Void> confirmScore(@RequestBody Map<String, Object> body) {
        Long periodId = Long.valueOf(body.get("periodId").toString());
        performanceService.confirmScore(periodId, SecurityUtils.getCurrentUserId());
        return ApiResult.success();
    }

    @PostMapping("/publish")
    @OperationLogAnnotation(action = "PUBLISH_FINAL_SCORE", entityType = "performance_score", sensitive = true)
    public ApiResult<PerformanceScore> publishFinalScore(@RequestBody Map<String, Object> body) {
        Long periodId = Long.valueOf(body.get("periodId").toString());
        Long targetUserId = Long.valueOf(body.get("userId").toString());
        return ApiResult.success(
                performanceService.publishFinalScore(periodId, targetUserId, SecurityUtils.getCurrentUserId()));
    }

    @GetMapping("/review-queue")
    @OperationLogAnnotation(action = "VIEW_REVIEW_QUEUE", entityType = "performance_score", sensitive = true)
    public ApiResult<List<ScoringDto>> reviewQueue(@RequestParam Long periodId) {
        return ApiResult.success(
                performanceService.getSubordinateScores(periodId, SecurityUtils.getCurrentUserId()));
    }

    @GetMapping("/history")
    @OperationLogAnnotation(action = "VIEW_SCORE_HISTORY", entityType = "performance_score", sensitive = true)
    public ApiResult<List<ScoringDto>> history() {
        return ApiResult.success(
                performanceService.getMyHistory(SecurityUtils.getCurrentUserId()));
    }

    @GetMapping("/subordinates")
    @OperationLogAnnotation(action = "VIEW_SUBORDINATE_SCORES", entityType = "performance_score", sensitive = true)
    public ApiResult<List<ScoringDto>> getSubordinates(@RequestParam Long periodId) {
        return ApiResult.success(
                performanceService.getSubordinateScores(periodId, SecurityUtils.getCurrentUserId()));
    }

    @PostMapping("/{id}/correction")
    @OperationLogAnnotation(action = "CORRECT_FINAL_SCORE", entityType = "performance_score", sensitive = true)
    public ApiResult<PerformanceScore> correctFinalScore(@PathVariable Long id, @RequestBody Map<String, Object> body) {
        return ApiResult.success(performanceService.correctFinalScore(
                id,
                SecurityUtils.getCurrentUserId(),
                toDouble(body.get("okrScore")),
                toDouble(body.get("kpiScore")),
                toDouble(body.get("bonus")),
                toDouble(body.get("penalty")),
                body.getOrDefault("commentsJson", "{}").toString(),
                body.getOrDefault("reason", "").toString()));
    }

    private Double toDouble(Object val) {
        if (val == null) return 0.0;
        if (val instanceof Number n) return n.doubleValue();
        return Double.parseDouble(val.toString());
    }
}
