#!/usr/bin/env python

from __future__ import annotations

import os
import pexpect
import sys


env_vars = {
    'ANSIBLE_ROLES_PATH': './roles',
    'ANSIBLE_NOCOLOR': 'True',
    'ANSIBLE_RETRY_FILES_ENABLED': 'False',
}


def run_test(playbook, test_spec, args=None, timeout=10, env=None):

    if not env:
        env = os.environ.copy()
    env.update(env_vars)

    if not args:
        args = sys.argv[1:]

    vars_prompt_test = pexpect.spawn(
        'ansible-playbook',
        args=[playbook] + args,
        timeout=timeout,
        env=env,
    )

    vars_prompt_test.logfile = sys.stdout.buffer
    for item in test_spec[0]:
        vars_prompt_test.expect(item[0])
        if item[1]:
            vars_prompt_test.send(item[1])
    vars_prompt_test.expect(test_spec[1])
    vars_prompt_test.expect(pexpect.EOF)
    vars_prompt_test.close()


# These are the tests to run. Each test is a playbook and a test_spec.
#
# The test_spec is a list with two elements.
#
# The first element is a list of two element tuples. The first is the regexp to look
# for in the output, the second is the line to send.
#
# The last element is the last string of text to look for in the output.
#
tests = [
    # Basic vars_prompt
    {'playbook': 'vars_prompt-1.yml',
     'test_spec': [
        [('input:', 'some input\r')],
         '"input": "some input"']},

    # Custom prompt
    {'playbook': 'vars_prompt-2.yml',
     'test_spec': [
         [('Enter some input:', 'some more input\r')],
         '"input": "some more input"']},

    # Test confirm, both correct and incorrect
    {'playbook': 'vars_prompt-3.yml',
     'test_spec': [
         [('input:', 'confirm me\r'),
          ('confirm input:', 'confirm me\r')],
         '"input": "confirm me"']},

    {'playbook': 'vars_prompt-3.yml',
     'test_spec': [
         [('input:', 'confirm me\r'),
          ('confirm input:', 'incorrect\r'),
          (r'\*\*\*\*\* VALUES ENTERED DO NOT MATCH \*\*\*\*', ''),
          ('input:', 'confirm me\r'),
          ('confirm input:', 'confirm me\r')],
         '"input": "confirm me"']},

    # Test private
    {'playbook': 'vars_prompt-4.yml',
     'test_spec': [
         [('not_secret', 'this is displayed\r'),
          ('this is displayed', '')],
         '"not_secret": "this is displayed"']},

    # Test hashing
    {'playbook': 'vars_prompt-5.yml',
     'test_spec': [
         [('password', 'Scenic-Improving-Payphone\r'),
          ('confirm password', 'Scenic-Improving-Payphone\r')],
         r'"password": "\$6\$']},

    # Test variables in prompt field
    # https://github.com/ansible/ansible/issues/32723
    {'playbook': 'vars_prompt-6.yml',
     'test_spec': [
         [('prompt from variable:', 'input\r')],
         '']},

    # Test play vars coming from vars_prompt
    # https://github.com/ansible/ansible/issues/37984
    {'playbook': 'vars_prompt-7.yml',
     'test_spec': [
         [('prompting for host:', 'testhost\r')],
         r'testhost.*ok=1']},

    # Test play unsafe toggle
    {'playbook': 'unsafe.yml',
     'test_spec': [
         [('prompting for variable:', '{{whole}}\r')],
         r'testhost.*ok=2']},

    # Test unsupported keys
    {'playbook': 'unsupported.yml',
     'test_spec': [
         [],
         "Invalid vars_prompt data structure, found unsupported key 'when'"]},
]

for t in tests:
    run_test(playbook=t['playbook'], test_spec=t['test_spec'])
