#!/usr/bin/env python

import jiav.constants
from jiav import exceptions, logger
from jiav.api import manifest
from jiav.utils import content
from jiav.utils.jira import JiraConnection

jiav_logger = logger.subscribe_to_logger()


def prepare_jiav_comment(
    successful=bool(False),
    status=str(),
    manifest_comment=None,
    upload_attachment=bool(False),
):
    """
    Prepares jiav comment containing the execution result

    Arguments:
        successful       - Result of jiav manifest execution

        status           - Desired status of verified issue

        manifest_comment - Jira comment containing jiav manifest

        attachment       - Attachment to uploaded if required

    Returns:
        generated_comment - Comment that will be posted
    """
    generated_comment = list()
    # If jiav manifest execution is successful
    generated_comment.append(f"*Executed manifest on comment ID: {manifest_comment}*")
    if successful:
        generated_comment.append("manifest executed successfully")
        generated_comment.append(f"Verifying issue as {status}")
    # If jiav manifest execution failed
    else:
        generated_comment.append("Failed to verify issue using provided manifest")
    if upload_attachment:
        generated_comment.append(
            "Uploading attachment of execution,*attachment is not private*."
        )
    else:
        generated_comment.append("Attachment was not uploaded, view logs on executor.")
    generated_comment.append(f"\nGenerated by jiav {jiav.constants.__VERSION__}")
    return "\n".join(generated_comment)


def process_comments(comments=list(), allow_public_comments=bool(False)):
    valid_manifest = None
    jiav_comment = None
    # Iterate over comments in reverse order (from last to first)
    for idx, comment in reversed(list(enumerate(comments))):
        jiav_logger.debug(f"Looking at comment #{idx}")
        # Attempt to validate comment according to jiav manifest
        if not allow_public_comments:
            try:
                comment.visibility.type
            except AttributeError:
                jiav_logger.debug(f"Comment {idx} is not private, skipping")
                continue
        try:
            valid_manifest = manifest.validate_manifest(text=comment.body)
        except exceptions.InvalidManifestException:
            jiav_logger.debug(f"Comment {idx} does not contain a valid manifest")
        if valid_manifest:
            jiav_comment = comment
            break
    return valid_manifest, jiav_comment


def verify_issues(
    issues=list(),
    jira_connection=type(JiraConnection),
    upload_attachment=bool(False),
    allow_public_comments=bool(False),
    dry_run=bool(False),
):
    """
    Attempts to verify issues

    Arguments:
        issues - List of issues from jiav.utils.jira.discover_valid_issues function

        jira_connection - Jira connection object defined by
        jiav.utils.jira.JiraConnection

        upload_attacment - Upload attachment if requested

        public_comment_allowed - Allow manifest from public comments

        dry_run - Do not update issues

    Returns:
        verified_issues - List of issues that were successfully verified
    """
    # Init variables
    verified_issues = list()
    if dry_run:
        jiav_logger.info("Will not update issues, running as dry run")
    # Iterate over issues
    for issue in issues:
        manifest_comment = None
        jiav_manifest = None
        desired_status = str()
        jiav_logger.info(f"Looking at issue {issue}")
        jiav_manifest, manifest_comment = process_comments(
            comments=issue.fields.comment.comments,
            allow_public_comments=allow_public_comments,
        )
        # If valid manifest was provided in comments
        if isinstance(jiav_manifest, manifest.Manifest):
            jiav_logger.info(f"Valid manifest was found in issue {issue}")
            desired_status = jiav_manifest.verified_status
            # If issue is already in the desired status, we skip it
            if desired_status == issue.fields.status.name:
                jiav_logger.info(
                    f"""Issue {issue} is already verified with status
{desired_status}"""
                )
                break
            transition_id = jira_connection.check_if_status_is_valid(
                issue=issue, desired_status=desired_status
            )
            if not transition_id:
                jiav_logger.error(
                    f"""Desired status {desired_status} is not valid in this
instance"""
                )
                break
            # Execute according to jiav request
            jiav_manifest.execute_manifest()
            if not dry_run:
                comment = prepare_jiav_comment(
                    successful=jiav_manifest.successful,
                    status=jiav_manifest.verified_status,
                    manifest_comment=manifest_comment,
                    upload_attachment=upload_attachment,
                )
                # Post comment with the execution result
                jira_connection.post_comment(issue=issue, comment=comment)

                # Add attachment if requested by user
                if upload_attachment:
                    # Generate tempfile with the jiav manifest execution output
                    temp_file = content.write_content_to_tempfile(
                        jiav_manifest.execution_output
                    )
                    jira_connection.upload_attachment(
                        issue=issue, file_path=temp_file.name
                    )

                # If manifest executed successfully
                if jiav_manifest.successful:
                    jira_connection.update_issue_status(
                        issue=issue, transition_id=transition_id
                    )
                    verified_issues.append(issue)
        else:
            jiav_logger.info(f"Valid manifest was not found in issue {issue}")
    return verified_issues
