package com.arms.api.issue.status.strategy;

import com.arms.api.issue.status.model.dto.IssueStatusCategoryDTO;
import com.arms.api.issue.status.model.dto.IssueStatusDTO;
import com.arms.api.issue.status.model.dto.CloudJiraByIssueTypeIssueStatusDTO;
import com.arms.api.issue.status.model.vo.CloudJiraByIssueTypeIssueStatusVO;
import com.arms.api.issue.status.model.vo.IssueStatusCategoryVO;
import com.arms.api.issue.status.model.vo.IssueStatusVO;
import com.arms.api.serverinfo.model.vo.ServerInfoVO;
import com.arms.api.serverinfo.service.ServerInfoService;
import com.arms.api.util.alm.JiraApi;
import com.arms.api.util.alm.JiraUtil;
import com.arms.api.util.errors.ErrorLogUtil;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.client.WebClient;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Component
@AllArgsConstructor
public class CloudJiraIssueStatusStrategy implements IssueStatusStrategy {

    private final JiraUtil jiraUtil;

    private final JiraApi jiraApi;

    private final ServerInfoService serverInfoService;

    @Override
    public List<IssueStatusVO> getIssueStatusList(ServerInfoVO serverInfoVO) {
        return null;
    }

    @Override
    public List<CloudJiraByIssueTypeIssueStatusVO> getIssueStatusListByProject(ServerInfoVO serverInfoVO, String projectId) {

        String endpoint = jiraApi.getEndpoint().getProject() + "/" + projectId + "/statuses";
        WebClient webClient = jiraUtil.createJiraCloudCommunicator(serverInfoVO.getUri(), serverInfoVO.getUserId(),
                serverInfoService.getDecryptPasswordOrToken(serverInfoVO.getPasswordOrToken()));

        try {
            List<CloudJiraByIssueTypeIssueStatusDTO> issueStatusList
                    = jiraUtil.get(webClient, endpoint,
                            new ParameterizedTypeReference<List<CloudJiraByIssueTypeIssueStatusDTO>>() {}
                        ).block();

            return Optional.ofNullable(issueStatusList)
                    .orElse(Collections.emptyList())
                    .stream()
                    .filter(Objects::nonNull)
                    .map(this::convertCloudJiraByIssueTypeIssueStatusVO)
                    .collect(Collectors.toList());
        }
        catch (Exception e) {
            String errorMessage = ErrorLogUtil.exceptionLoggingAndReturn(e, this.getClass().getName(),
                    String.format("%s[%s] :: getIssueStatusListByProject Error :: projectId[%s]",
                                serverInfoVO.getType(), serverInfoVO.getUri(), projectId));

            throw new IllegalArgumentException(errorMessage);
        }
    }

    private CloudJiraByIssueTypeIssueStatusVO convertCloudJiraByIssueTypeIssueStatusVO(CloudJiraByIssueTypeIssueStatusDTO cloudJiraByIssueTypeIssueStatusDTO) {
        return CloudJiraByIssueTypeIssueStatusVO.builder()
                .self(cloudJiraByIssueTypeIssueStatusDTO.getSelf())
                .id(cloudJiraByIssueTypeIssueStatusDTO.getId())
                .name(cloudJiraByIssueTypeIssueStatusDTO.getName())
                .subtask(cloudJiraByIssueTypeIssueStatusDTO.isSubtask())
                .statuses(this.convertIssueStatusVOList(cloudJiraByIssueTypeIssueStatusDTO.getStatuses()))
                .build();
    }

    private List<IssueStatusVO> convertIssueStatusVOList(List<IssueStatusDTO> issueStatusDTOList) {
        return Optional.ofNullable(issueStatusDTOList)
                .orElse(Collections.emptyList())
                .stream()
                .filter(Objects::nonNull)
                .map(this::converIssueStatusVO)
                .collect(Collectors.toList());
    }

    private IssueStatusVO converIssueStatusVO(IssueStatusDTO issueStatusDTO) {
        return IssueStatusVO.builder()
                .self(issueStatusDTO.getSelf())
                .id(issueStatusDTO.getId())
                .name(issueStatusDTO.getName())
                .description(issueStatusDTO.getDescription())
                .issueTypeId(issueStatusDTO.getIssueTypeId())
                .statusCategory(Optional.ofNullable(issueStatusDTO.getStatusCategory())
                        .map(this::convertIssueStatusCategoryVO)
                        .orElse(null))
                .build();
    }

    private IssueStatusCategoryVO convertIssueStatusCategoryVO(IssueStatusCategoryDTO issueStatusCategoryDTO) {
        return IssueStatusCategoryVO.builder()
                .self(issueStatusCategoryDTO.getSelf())
                .id(issueStatusCategoryDTO.getId())
                .name(issueStatusCategoryDTO.getName())
                .key(issueStatusCategoryDTO.getKey())
                .colorName(issueStatusCategoryDTO.getColorName())
                .build();
    }
}
