#!/usr/bin/python3 -u
# Like what you see? Join us!
# https://www.univention.com/about-us/careers/vacancies/
#
# SPDX-FileCopyrightText: 2024 Univention GmbH
# SPDX-License-Identifier: AGPL-3.0-only

"""UCS Testrunner - run UCS test in sane environment."""

from __future__ import annotations

import os
import sys
from argparse import REMAINDER, ArgumentParser, FileType, Namespace
from typing import Sequence

import univention.testing.format
from univention.testing.data import TestCase, TestEnvironment, TestResult
from univention.testing.internal import setup_debug, setup_environment


def parse_args(args: Sequence[str] | None = None) -> Namespace:
    """
    Parse command line arguments.

    This is used as a hash-bang like
    > #!/usr/share/ucs-test/runner bash -e
    When test "./00_foo -vf" is executed this gets translated to
    > /usr/share/ucs-test/runner "bash -e" ./00_foo -v -f
    "-v -f" are collected in `args` and must be passed again to get applied to `runner` itself.

    >>> parse_args(["bash", "/dev/null"]) #doctest: +ELLIPSIS
    Namespace(args=[], force=False, format='text', interpreter='bash', test=<open file '/dev/null', mode 'r' at ...>, verbose=None)
    >>> parse_args(["--verbose", "--force", "--format=text", "bash", "/dev/null"]) #doctest: +ELLIPSIS
    Namespace(args=[], force=True, format='text', interpreter='bash', test=<open file '/dev/null', mode 'r' at ...>, verbose=1)
    >>> parse_args(["bash", "/dev/null", "--verbose", "--force", "--format=text"]) #doctest: +ELLIPSIS
    Namespace(args=[], force=True, format='text', interpreter='bash', test=<open file '/dev/null', mode 'r' at ...>, verbose=1)
    """
    common = ArgumentParser(add_help=False)
    common.add_argument("--verbose", "-v", action="count", help="Increase verbosity")
    common.add_argument("--force", "-f", action="store_true", help="Disable pre-condition check")
    common.add_argument("--format", "-F", choices=univention.testing.format.FORMATS, default='text', help="Select output format [%(default)s]")
    common.add_argument(
        "-i", "--interactive",
        action="store_true",
        help="Execute commands in an interactive shell",
        default=(os.isatty(1) and os.isatty(2)),
    )  # The new default is there to fix `Failed to open /dev/tty [...]` in tests

    parser = ArgumentParser(parents=[common])
    parser.add_argument("interpreter", help="Command interpreter")
    parser.add_argument("test", type=FileType("r"), help="ucs-test filename")
    parser.add_argument('args', nargs=REMAINDER, help="Additional arguments")

    options = parser.parse_args(args)
    if options.args:
        options = common.parse_args(args=options.args, namespace=options)
        del options.args[:]

    return options


def main() -> int:
    """Run single UCS test."""
    options = parse_args()

    setup_environment()
    setup_debug(options.verbose)

    del sys.argv[0:2]

    formatter = getattr(univention.testing.format, f'format_{options.format}')
    format = formatter()
    test_env = TestEnvironment(interactive=options.interactive)
    if options.force:
        test_env.set_exposure('dangerous')
    test_case = TestCase(options.test.name).load()
    test_result = TestResult(test_case, test_env).run()
    format.format(test_result)
    return 0 if test_result.reason.eofs in {'O', 'S'} else 1


if __name__ == '__main__':
    try:
        sys.exit(main())
    except KeyboardInterrupt:
        sys.exit(1)
