package com.atlassian.bitbucket.integration.jira.web;

import com.atlassian.bitbucket.integration.jira.JiraConstants;
import com.atlassian.integration.jira.JiraIssueUrlsRequest;
import com.atlassian.integration.jira.JiraService;
import com.atlassian.plugin.web.Condition;
import com.atlassian.bitbucket.commit.Commit;
import org.apache.commons.collections.CollectionUtils;

import java.util.Map;
import java.util.Set;

/**
 * A condition which can be used to determine whether JIRA issues should be shown.
 * <p>
 * This condition expects a "commit" in the context. It retrieves {@link JiraConstants#IDX_PROP_ISSUE_KEYS issue keys}
 * associated with the commit and, if there are any, returns {@code true} to display the associated UI component
 * <i>if</i> there is a linked JIRA instance. If there is no linked JIRA instance, issues associated with the commit
 * are ignored and this condition returns {@code false}.
 */
public class ShouldDisplayIssueSectionCondition implements Condition {

    private final JiraService jiraService;

    public ShouldDisplayIssueSectionCondition(JiraService jiraService) {
        this.jiraService = jiraService;
    }

    @Override
    public void init(Map<String, String> initParams) {
    }

    @Override
    public boolean shouldDisplay(Map<String, Object> context) {
        return jiraService.isLinked() && hasJiraKeys(context);
    }

    /**
     * Determines whether issue keys are available in the provided {@code context}.
     *
     * @param context the context for the panel
     * @return {@code true} if issue keys are (or may be) present; otherwise, {@code false}
     */
    public boolean hasJiraKeys(Map<String, Object> context) {
        Commit commit = (Commit) context.get("commit");
        if (commit == null) {
            //If there is no commit, this condition must be being evaluated in a multi-commit context, such
            //as the commit list for a repository. In such contexts, as long as at least one JIRA instance is
            //linked (checked in shouldDisplay), the panel should always be shown
            return true;
        }

        //If there is a single commit, the issue panel should only be displayed if the issue has at least one
        //issue key associated with it _and_ URLs are available.
        //
        //NOTE: If you change this, SimpleJiraIssueContextProvider most likely needs to be changed too.
        @SuppressWarnings("unchecked")
        Set<String> issueKeys = (Set) commit.getProperties().get(JiraConstants.IDX_PROP_ISSUE_KEYS);
        if (CollectionUtils.isEmpty(issueKeys)) {
            //There are no issue keys, so there is no need to display the panel
            return false;
        }
        if (issueKeys.size() > 1) {
            //If there are multiple issue keys, the exact keys are not shown in the panel and the dialog must be
            //opened to see them. No need to check URLs; just return true
            return true;
        }

        //Otherwise, if there is only a single issue, make sure a URL is available for that issue. If one isn't,
        //then the panel should not be displayed because it means the issue doesn't exist (or can't be viewed)
        Map<String, String> urls = jiraService.getIssueUrls(new JiraIssueUrlsRequest.Builder()
                                                            .issueKeys(issueKeys)
                                                            .build());

        return !urls.isEmpty();
    }
}
