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

import com.arms.api.issue.type.model.vo.IssueTypeVO;
import com.arms.api.serverinfo.model.vo.ServerInfoVO;
import com.arms.api.serverinfo.service.ServerInfoService;
import com.arms.api.util.alm.RedmineApi;
import com.arms.api.util.alm.RedmineUtil;
import com.arms.api.util.errors.ErrorLogUtil;
import com.taskadapter.redmineapi.RedmineException;
import com.taskadapter.redmineapi.RedmineManager;
import com.taskadapter.redmineapi.bean.Project;
import com.taskadapter.redmineapi.bean.Tracker;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Objects;

import static java.util.stream.Collectors.toList;

@Component
@AllArgsConstructor
public class OnpremiseRedmineIssueTypeStrategy implements IssueTypeStrategy {

    private final RedmineUtil redmineUtil;

    private final RedmineApi redmineApi;

    private final ServerInfoService serverInfoService;

    @Override
    public List<IssueTypeVO> getIssueTypeList(ServerInfoVO serverInfoVO) {

        RedmineManager redmineManager = redmineUtil.createRedmineOnPremiseCommunicator(serverInfoVO.getUri(), serverInfoService.getDecryptPasswordOrToken(serverInfoVO.getPasswordOrToken()));
        try {
            List<Tracker> redmineIssueTypeList = redmineManager.getIssueManager().getTrackers();

            List<IssueTypeVO> issueTypeList = redmineIssueTypeList.stream()
                    .map(issueType -> this.convertIssueTypeVO(issueType, serverInfoVO.getUri(), null))
                    .filter(Objects::nonNull)
                    .collect(toList());

            return issueTypeList;
        }
        catch (RedmineException e) {
            String errorMessage = ErrorLogUtil.exceptionLoggingAndReturn(e, this.getClass().getName(),
                    String.format("%s[%s] :: getIssueTypeList Error", serverInfoVO.getType(), serverInfoVO.getUri()));
            throw new IllegalArgumentException(errorMessage);
        }
    }

    @Override
    public List<IssueTypeVO> getIssueTypeListByProject(ServerInfoVO serverInfoVO, String projectId) {

        RedmineManager redmineManager = redmineUtil.createRedmineOnPremiseCommunicator(serverInfoVO.getUri(), serverInfoService.getDecryptPasswordOrToken(serverInfoVO.getPasswordOrToken()));
        Project project;
        try {
            project = redmineManager.getProjectManager().getProjectById(Integer.parseInt(projectId));
        }
        catch (RedmineException e) {
            String errorMessage = ErrorLogUtil.exceptionLoggingAndReturn(e, this.getClass().getName(),
                    String.format("%s[%s] :: getIssueTypeListByProject Error :: projectId[%s]",
                                serverInfoVO.getType(), serverInfoVO.getUri(), projectId));
            throw new IllegalArgumentException(errorMessage);
        }

        List<IssueTypeVO> issueTypeList = project.getTrackers()
                .stream()
                .map(redmineIssueType -> {
                    IssueTypeVO issueTypeVO = this.convertIssueTypeVO(redmineIssueType, serverInfoVO.getUri(), projectId);
                    return issueTypeVO;
                })
                .filter(Objects::nonNull)
                .collect(toList());

        return issueTypeList;
    }

    private IssueTypeVO convertIssueTypeVO(Tracker redmineIssueType, String serverUri, String projectId) {

        IssueTypeVO.IssueTypeVOBuilder builder = IssueTypeVO.builder();
        String issueTypeEndpoint = redmineApi.replaceID(redmineApi.getEndpoint().getIssuetype(), String.valueOf(redmineIssueType.getId()));
        String issueTypeSelf = redmineUtil.checkServerInfoPath(serverUri) + issueTypeEndpoint;
        if (StringUtils.isNotEmpty(projectId)) {
            builder.self(issueTypeSelf + "&project_id=" + projectId);
        }
        else {
            builder.self(issueTypeSelf);
        }

        return builder.id(redmineIssueType.getId().toString())
                .name(redmineIssueType.getName())
                .subtask(false).build();
    }
}
