package com.arms.api.mapping.controller;

import com.arms.api.mapping.domain.AlmIssueStatus;
import com.arms.api.mapping.domain.StateCategory;
import com.arms.api.mapping.dto.AlmServerRequestDTO;
import com.arms.api.mapping.dto.StateCategoryDTO;
import com.arms.api.mapping.dto.StateDTO;
import com.arms.api.mapping.service.AlmIssueStatusService;
import com.arms.api.mapping.service.StateCategoryService;
import com.arms.api.mapping.service.StateService;
import com.arms.api.util.redisrepo.util.RedisUtil;
import com.arms.api.util.response.CommonResponse;
import com.arms.api.util.response.CommonResponse.ApiResult;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.stream.Collectors;

import static com.arms.api.util.response.CommonResponse.success;

@Slf4j
@AllArgsConstructor
@RestController
@RequestMapping("/mapping")
public class MappingController {

    private final StateService stateService;
    private final StateCategoryService stateCategoryService;
    private final AlmIssueStatusService almIssueStatusService;

    @PostMapping("/alm/issuestatus")
    public Mono<CommonResponse.ApiResult<String>> almIssueStatusInit(@RequestBody AlmServerRequestDTO almServerRequestDTO) {

        if (almServerRequestDTO == null) {
            throw new RuntimeException("Alm Server Data가 없습니다.");
        }

        String pattern = RedisUtil.getRedisHashPrefix(AlmIssueStatus.class) + ":" +
                this.generateDeletePattern(almServerRequestDTO.getServerId(),almServerRequestDTO.getProjectKeyOrId(), almServerRequestDTO.getIssueTypeId()) + "*";
        almIssueStatusService.deleteAlmIssueStatus(pattern);

        almIssueStatusService.initAlmIssueStatus(
                almServerRequestDTO.getIssueStatusDTOs()
                        .stream()
                        .map(almIssueStatusDTO -> {
                            String key = this.generateKey(almServerRequestDTO.getServerId(), almServerRequestDTO.getProjectKeyOrId(),
                                    almServerRequestDTO.getIssueTypeId(), almIssueStatusDTO.getId());
                            almIssueStatusDTO.setId(key);

                            return almIssueStatusDTO.toEntity();
                        })
                        .collect(Collectors.toList())
        );

        return Mono.just(success("OK"));
    }

    @PostMapping("/state")
    public Mono<ApiResult<String>> initState(@RequestBody List<StateDTO> stateDTOs) {

        if (stateDTOs == null) {
            throw new RuntimeException("ARMS State Data가 없습니다.");
        }

        stateService.deleteState();

        stateService.init(
            stateDTOs
                .stream()
                .map(StateDTO::toEntity)
                .collect(Collectors.toList())
        );

        return Mono.just(success("OK"));
    }

    @PostMapping("/category")
    public Mono<ApiResult<String>> initCategory(@RequestBody List<StateCategoryDTO> stateCategoryDTOs) {

        if (stateCategoryDTOs == null) {
            throw new RuntimeException("ARMS State Category Data가 없습니다.");
        }

        stateCategoryService.deleteStateCategory();

        stateCategoryService.init(
                stateCategoryDTOs
                        .stream()
                        .map(StateCategoryDTO::toEntity)
                        .collect(Collectors.toList())
        );

        return Mono.just(success("OK"));
    }

    @GetMapping("/category")
    public Mono<ApiResult<StateCategory>> findStateCategory(@RequestParam("serverId") String serverId,
                                                            @RequestParam(value = "projectKey", required = false) String projectKey,
                                                            @RequestParam(value = "issueTypeId", required = false) String issueTypeId,
                                                            @RequestParam("issueStatusId") String issueStatusId) {

        String key = this.generateKey(serverId, projectKey, issueTypeId, issueStatusId);
        AlmIssueStatus almIssueStatus = almIssueStatusService.getAlmIssueStatus(key);
        String armsStateMappingId = almIssueStatus.getArmsStateMappingId();

        return Mono.just(success(stateCategoryService.getArmsStateCategoryByStateId(armsStateMappingId)));
    }

    private String generateKey(String serverId, String projectKeyOrId, String issueTypeId, String issueStatusId) {
        if (serverId == null || issueStatusId == null) {
            throw new IllegalArgumentException("serverId and issueStatusId cannot be null");
        }

        if (projectKeyOrId == null && issueTypeId == null) {
            return String.format("%s-%s", serverId, issueStatusId);
        }

        return String.format("%s-%s-%s-%s",
                        serverId,
                        projectKeyOrId != null ? projectKeyOrId : "",
                        issueTypeId != null ? issueTypeId : "",
                        issueStatusId
                ).replaceAll("-{2,}", "-")
                .replaceAll("-$", "");
    }

    private String generateDeletePattern(String serverId, String projectKeyOrId, String issueTypeId) {
        if (serverId == null) {
            throw new IllegalArgumentException("serverId cannot be null");
        }

        if (projectKeyOrId == null && issueTypeId == null) {
            return String.format("%s", serverId);
        }

        return String.format("%s-%s-%s",
                        serverId,
                        projectKeyOrId != null ? projectKeyOrId : "",
                        issueTypeId != null ? issueTypeId : ""
                ).replaceAll("-{2,}", "-")
                .replaceAll("-$", "");
    }
}

