package com.yimeng.okr.controller;

import com.yimeng.okr.annotation.OperationLogAnnotation;
import com.yimeng.okr.dto.ApiResult;
import com.yimeng.okr.dto.OkrDetailDto;
import com.yimeng.okr.entity.KrKeyResult;
import com.yimeng.okr.entity.KrProgressLog;
import com.yimeng.okr.enums.KrStatus;
import com.yimeng.okr.security.SecurityUtils;
import com.yimeng.okr.service.OkrService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;

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

@RestController
@RequestMapping("/api/okr")
@RequiredArgsConstructor
public class OkrController {

    private final OkrService okrService;

    @PostMapping("/submit")
    @OperationLogAnnotation(action = "SUBMIT_OKR", entityType = "okr_objective")
    public ApiResult<?> submitOkr(@RequestBody Map<String, Object> body) {
        Long periodId = Long.valueOf(body.get("periodId").toString());
        Long userId = SecurityUtils.getCurrentUserId();
        String title = body.get("title").toString();
        @SuppressWarnings("unchecked")
        List<Map<String, Object>> krList = (List<Map<String, Object>>) body.get("keyResults");
        List<KrKeyResult> krs = krList.stream().map(m -> {
            KrKeyResult kr = new KrKeyResult();
            kr.setTitle(m.get("title").toString());
            kr.setTargetValue(Double.valueOf(m.get("targetValue").toString()));
            kr.setWeight(m.get("weight") != null ? Integer.valueOf(m.get("weight").toString()) : 0);
            if (m.containsKey("assignedTo") && m.get("assignedTo") != null)
                kr.setAssignedTo(Long.valueOf(m.get("assignedTo").toString()));
            if (m.containsKey("sourceKrId") && m.get("sourceKrId") != null)
                kr.setSourceKrId(Long.valueOf(m.get("sourceKrId").toString()));
            return kr;
        }).toList();
        List<Long> alignedIds = new ArrayList<>();
        Object ao = body.get("alignedObjectiveIds");
        if (ao instanceof List<?> list) {
            for (Object item : list) alignedIds.add(Long.valueOf(item.toString()));
        }
        return ApiResult.success(okrService.submitOkr(periodId, userId, title, krs, alignedIds));
    }

    @PutMapping("/{id}/update")
    @OperationLogAnnotation(action = "UPDATE_OKR", entityType = "okr_objective")
    public ApiResult<?> updateMyOkr(@PathVariable Long id, @RequestBody Map<String, Object> body) {
        Long userId = SecurityUtils.getCurrentUserId();
        String title = body.get("title").toString();
        @SuppressWarnings("unchecked")
        List<Map<String, Object>> krList = (List<Map<String, Object>>) body.get("keyResults");
        List<KrKeyResult> krs = krList.stream().map(m -> {
            KrKeyResult kr = new KrKeyResult();
            kr.setTitle(m.get("title").toString());
            kr.setTargetValue(Double.valueOf(m.get("targetValue").toString()));
            kr.setWeight(m.get("weight") != null ? Integer.valueOf(m.get("weight").toString()) : 0);
            if (m.containsKey("assignedTo") && m.get("assignedTo") != null)
                kr.setAssignedTo(Long.valueOf(m.get("assignedTo").toString()));
            if (m.containsKey("sourceKrId") && m.get("sourceKrId") != null)
                kr.setSourceKrId(Long.valueOf(m.get("sourceKrId").toString()));
            return kr;
        }).toList();
        List<Long> alignedIds = new ArrayList<>();
        Object ao = body.get("alignedObjectiveIds");
        if (ao instanceof List<?> list) {
            for (Object item : list) alignedIds.add(Long.valueOf(item.toString()));
        }
        return ApiResult.success(okrService.updateMyOkr(id, userId, title, krs, alignedIds));
    }

    @PutMapping("/{id}/review")
    @OperationLogAnnotation(action = "REVIEW_OKR", entityType = "okr_objective")
    public ApiResult<Void> reviewOkr(@PathVariable Long id, @RequestBody Map<String, Object> body) {
        boolean approved = (boolean) body.get("approved");
        String remark = body.getOrDefault("remark", "").toString();
        okrService.reviewOkr(id, approved, remark, SecurityUtils.getCurrentUserId());
        return ApiResult.success();
    }

    @PutMapping("/kr/{krId}/progress")
    @OperationLogAnnotation(action = "UPDATE_KR_PROGRESS", entityType = "kr_key_result")
    public ApiResult<Void> updateKrProgress(@PathVariable Long krId, @RequestBody Map<String, Object> body) {
        Double newValue = Double.valueOf(body.get("newValue").toString());
        KrStatus newStatus = KrStatus.valueOf(body.get("status").toString());
        okrService.updateKrProgress(krId, newValue, newStatus,
                body.getOrDefault("remark", "").toString(), SecurityUtils.getCurrentUserId());
        return ApiResult.success();
    }

    @GetMapping("/kr/{krId}/history")
    public ApiResult<List<KrProgressLog>> getKrHistory(@PathVariable Long krId) {
        return ApiResult.success(okrService.getKrProgressHistory(krId, SecurityUtils.getCurrentUserId()));
    }

    @GetMapping("/period/{periodId}/superior")
    public ApiResult<List<OkrDetailDto>> getSuperiorOkrs(@PathVariable Long periodId) {
        return ApiResult.success(okrService.getSuperiorOkrs(periodId, SecurityUtils.getCurrentUserId()));
    }

    @GetMapping("/period/{periodId}/top-level")
    public ApiResult<List<OkrDetailDto>> getTopLevelOkrs(@PathVariable Long periodId) {
        return ApiResult.success(okrService.getTopLevelOkrs(periodId));
    }

    @GetMapping("/period/{periodId}/my")
    public ApiResult<OkrDetailDto> getMyOkr(@PathVariable Long periodId) {
        return ApiResult.success(okrService.getMyOkr(periodId, SecurityUtils.getCurrentUserId()));
    }

    @GetMapping("/period/{periodId}/can-submit")
    public ApiResult<Map<String, Boolean>> canSubmit(@PathVariable Long periodId) {
        return ApiResult.success(Map.of("canSubmit",
                okrService.canSubmitOkr(periodId, SecurityUtils.getCurrentUserId())));
    }

    @GetMapping("/period/{periodId}/subordinates")
    public ApiResult<List<OkrDetailDto>> getSubordinates(@PathVariable Long periodId) {
        return ApiResult.success(okrService.getSubordinateOkrs(periodId, SecurityUtils.getCurrentUserId()));
    }

    @GetMapping("/period/{periodId}/dept-members/{deptId}")
    public ApiResult<List<OkrDetailDto>> getDeptMembers(@PathVariable Long periodId, @PathVariable Long deptId) {
        return ApiResult.success(okrService.getDeptMemberOkrs(periodId, deptId, SecurityUtils.getCurrentUserId()));
    }

    @GetMapping("/period/{periodId}/pending-reviews")
    public ApiResult<List<OkrDetailDto>> getPendingReviews(@PathVariable Long periodId) {
        return ApiResult.success(okrService.getPendingReviews(periodId, SecurityUtils.getCurrentUserId()));
    }

    @GetMapping("/period/{periodId}/all")
    public ApiResult<List<OkrDetailDto>> getAllOkrs(@PathVariable Long periodId) {
        return ApiResult.success(okrService.getAllOkrsForPeriod(periodId, SecurityUtils.getCurrentUserId()));
    }

    @GetMapping("/workbench")
    public ApiResult<?> workbench(@RequestParam Long periodId) {
        Long userId = SecurityUtils.getCurrentUserId();
        return ApiResult.success(okrService.getWorkbench(periodId, userId));
    }

    @GetMapping("/{id}")
    public ApiResult<OkrDetailDto> getDetail(@PathVariable Long id) {
        return ApiResult.success(okrService.getOkrDetail(id, SecurityUtils.getCurrentUserId()));
    }

    @PostMapping("/submit-hierarchy")
    @OperationLogAnnotation(action = "SUBMIT_HIERARCHY_OKR", entityType = "okr_objective")
    public ApiResult<?> submitHierarchyOkr(@RequestBody Map<String, Object> body) {
        Long periodId = Long.valueOf(body.get("periodId").toString());
        Long userId = SecurityUtils.getCurrentUserId();
        String title = body.get("title").toString();
        String level = body.getOrDefault("level", "INDIVIDUAL").toString();
        Long parentObjectiveId = body.get("parentObjectiveId") != null
                ? Long.valueOf(body.get("parentObjectiveId").toString()) : null;
        @SuppressWarnings("unchecked")
        List<Map<String, Object>> krList = (List<Map<String, Object>>) body.get("keyResults");
        List<KrKeyResult> krs = krList.stream().map(m -> {
            KrKeyResult kr = new KrKeyResult();
            kr.setTitle(m.get("title").toString());
            kr.setTargetValue(Double.valueOf(m.get("targetValue").toString()));
            kr.setWeight(m.get("weight") != null ? Integer.valueOf(m.get("weight").toString()) : 0);
            return kr;
        }).toList();
        List<Long> alignedIds = new ArrayList<>();
        Object ao = body.get("alignedObjectiveIds");
        if (ao instanceof List<?> list) {
            for (Object item : list) alignedIds.add(Long.valueOf(item.toString()));
        }
        return ApiResult.success(okrService.submitHierarchyOkr(periodId, userId, title, krs, level, parentObjectiveId, alignedIds));
    }

    @GetMapping("/period/{periodId}/tree")
    public ApiResult<List<OkrDetailDto>> getOkrTree(@PathVariable Long periodId) {
        return ApiResult.success(okrService.getOkrTree(periodId, SecurityUtils.getCurrentUserId()));
    }

    @GetMapping("/period/{periodId}/orphans")
    public ApiResult<List<OkrDetailDto>> getOrphanOkrs(@PathVariable Long periodId) {
        return ApiResult.success(okrService.getOrphanOkrs(periodId, SecurityUtils.getCurrentUserId()));
    }

    @PostMapping("/{id}/align")
    @OperationLogAnnotation(action = "ALIGN_OKR", entityType = "okr_objective")
    public ApiResult<Void> setAlignment(@PathVariable Long id, @RequestBody Map<String, Object> body) {
        Long parentId = body.get("parentObjectiveId") != null
                ? Long.valueOf(body.get("parentObjectiveId").toString()) : null;
        okrService.setAlignment(id, parentId, SecurityUtils.getCurrentUserId());
        return ApiResult.success();
    }

    @GetMapping("/{id}/children")
    public ApiResult<List<OkrDetailDto>> getChildren(@PathVariable Long id) {
        return ApiResult.success(okrService.getChildren(id, SecurityUtils.getCurrentUserId()));
    }
}
