#!/usr/bin/python3 -u
# SPDX-FileCopyrightText: 2024-2026 Univention GmbH
# SPDX-License-Identifier: AGPL-3.0-only

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


import os
import sys
from argparse import REMAINDER, ArgumentParser, FileType, Namespace
from collections.abc 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)
