import os
import logging
import pytest
from jenkinsapi.jenkins import Jenkins
from jenkinsapi_utils.jenkins_launcher import JenkinsLancher

log = logging.getLogger(__name__)
state = {}

# User/password for authentication testcases
ADMIN_USER = 'admin'
ADMIN_PASSWORD = 'admin'

# Extra plugins required by the systests
PLUGIN_DEPENDENCIES = [
    "http://updates.jenkins.io/latest/"
    "apache-httpcomponents-client-4-api.hpi",
    "http://updates.jenkins.io/latest/jsch.hpi",
    "http://updates.jenkins.io/download/plugins/trilead-api/1.0.5/"
    "trilead-api.hpi",
    "http://updates.jenkins.io/latest/workflow-api.hpi",
    "http://updates.jenkins.io/latest/display-url-api.hpi",
    "http://updates.jenkins.io/latest/workflow-step-api.hpi",
    "http://updates.jenkins.io/latest/workflow-scm-step.hpi",
    "http://updates.jenkins.io/latest/icon-shim.hpi",
    "http://updates.jenkins.io/download/plugins/junit/1.28/junit.hpi",
    "http://updates.jenkins.io/latest/script-security.hpi",
    "http://updates.jenkins.io/latest/matrix-project.hpi",
    "http://updates.jenkins.io/latest/credentials.hpi",
    "http://updates.jenkins.io/latest/ssh-credentials.hpi",
    "http://updates.jenkins.io/latest/scm-api.hpi",
    "http://updates.jenkins.io/latest/mailer.hpi",
    "http://updates.jenkins.io/latest/git.hpi",
    "http://updates.jenkins.io/latest/git-client.hpi",
    "https://updates.jenkins.io/latest/nested-view.hpi",
    "https://updates.jenkins.io/latest/ssh-slaves.hpi",
    "https://updates.jenkins.io/latest/structs.hpi",
    "http://updates.jenkins.io/latest/plain-credentials.hpi",
    "http://updates.jenkins.io/latest/envinject.hpi",
    "http://updates.jenkins.io/latest/envinject-api.hpi",
    "http://updates.jenkins.io/latest/jdk-tool.hpi"
]


def _delete_all_jobs(jenkins):
    jenkins.poll()
    for name in jenkins.keys():
        del jenkins[name]


def _delete_all_views(jenkins):
    all_view_names = jenkins.views.keys()[1:]
    for name in all_view_names:
        del jenkins.views[name]


def _delete_all_credentials(jenkins):
    all_cred_names = jenkins.credentials.keys()
    for name in all_cred_names:
        del jenkins.credentials[name]


def _create_admin_user(launched_jenkins):
    # Groovy script that creates a user "admin/admin" in jenkins
    # and enable security. "admin" user will be the only user and
    # have admin permissions. Anonymous cannot read anything.
    create_admin_groovy = """
import jenkins.model.*
import hudson.security.*

def instance = Jenkins.getInstance()

def hudsonRealm = new HudsonPrivateSecurityRealm(false)
hudsonRealm.createAccount('{0}','{1}')
instance.setSecurityRealm(hudsonRealm)

def strategy = new FullControlOnceLoggedInAuthorizationStrategy()
strategy.setAllowAnonymousRead(false)
instance.setAuthorizationStrategy(strategy)
    """.format(ADMIN_USER, ADMIN_PASSWORD)

    url = launched_jenkins.jenkins_url
    jenkins_instance = Jenkins(url)
    jenkins_instance.run_groovy_script(create_admin_groovy)


def _disable_security(launched_jenkins):
    # Groovy script that disables security in jenkins,
    # reverting the changes made in "_create_admin_user" function.
    disable_security_groovy = """
import jenkins.model.*
import hudson.security.*

def instance = Jenkins.getInstance()
instance.disableSecurity()
instance.save()
    """

    url = launched_jenkins.jenkins_url
    jenkins_instance = Jenkins(url, ADMIN_USER, ADMIN_PASSWORD)
    jenkins_instance.run_groovy_script(disable_security_groovy)


@pytest.fixture(scope='session')
def launched_jenkins():
    systests_dir, _ = os.path.split(__file__)
    local_orig_dir = os.path.join(systests_dir, 'localinstance_files')
    if not os.path.exists(local_orig_dir):
        os.mkdir(local_orig_dir)
    war_name = 'jenkins.war'
    launcher = JenkinsLancher(
        local_orig_dir, systests_dir, war_name, PLUGIN_DEPENDENCIES,
        jenkins_url=os.getenv('JENKINS_URL', None)
    )
    launcher.start()

    yield launcher

    log.info('All tests finished')
    launcher.stop()


@pytest.fixture(scope='function')
def jenkins(launched_jenkins):
    url = launched_jenkins.jenkins_url

    jenkins_instance = Jenkins(url, timeout=30)

    _delete_all_jobs(jenkins_instance)
    _delete_all_views(jenkins_instance)
    _delete_all_credentials(jenkins_instance)

    return jenkins_instance


@pytest.fixture(scope='function')
def lazy_jenkins(launched_jenkins):
    url = launched_jenkins.jenkins_url

    jenkins_instance = Jenkins(url, lazy=True)

    _delete_all_jobs(jenkins_instance)
    _delete_all_views(jenkins_instance)
    _delete_all_credentials(jenkins_instance)

    return jenkins_instance


@pytest.fixture(scope='function')
def jenkins_admin_admin(launched_jenkins, jenkins):  # pylint: disable=unused-argument
    # Using "jenkins" fixture makes sure that jobs/views/credentials are
    # cleaned before security is enabled.
    url = launched_jenkins.jenkins_url

    _create_admin_user(launched_jenkins)
    jenkins_admin_instance = Jenkins(url, ADMIN_USER, ADMIN_PASSWORD)

    yield jenkins_admin_instance

    jenkins_admin_instance.requester.__class__.AUTH_COOKIE = None
    _disable_security(launched_jenkins)
