#!/usr/bin/python
# coding: utf-8 -*-

# Copyright (c) 2023, Takuya Nishimura <@nishipy>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import absolute_import, division, print_function

__metaclass__ = type

DOCUMENTATION = r"""
module: podman_container_exec
author:
  - Takuya Nishimura (@nishipy)
short_description: Executes a command in a running container.
description:
  - Executes a command in a running container.
options:
  name:
    description:
      - Name of the container where the command is executed.
    type: str
    required: true
  command:
    description:
      - The command to run in the container.
      - One of the I(command) or I(args) is required.
    type: str
  argv:
    description:
      - Passes the command as a list rather than a string.
      - One of the I(command) or I(args) is required.
    type: list
    elements: str
  detach:
    description:
      - If true, the command runs in the background.
      - The exec session is automatically removed when it completes.
    type: bool
    default: false
  env:
    description:
      - Set environment variables.
    type: dict
  executable:
    description:
        - The path to the podman executable.
    type: str
    default: podman
  privileged:
    description:
      - Give extended privileges to the container.
    type: bool
    default: false
  tty:
    description:
      - Allocate a pseudo-TTY.
    type: bool
    default: false
  user:
    description:
      - The username or UID used and, optionally, the groupname or GID for the specified command.
      - Both user and group may be symbolic or numeric.
    type: str
  workdir:
    description:
      - Working directory inside the container.
    type: str
requirements:
  - podman
notes:
  - See L(the Podman documentation,https://docs.podman.io/en/latest/markdown/podman-exec.1.html) for details of podman-exec(1).
"""

EXAMPLES = r"""
- name: Execute a command with workdir
  containers.podman.podman_container_exec:
    name: ubi8
    command: "cat redhat-release"
    workdir: /etc

- name: Execute a command with a list of args and environment variables
  containers.podman.podman_container_exec:
    name: test_container
    argv:
      - /bin/sh
      - -c
      - echo $HELLO $BYE
    env:
      HELLO: hello world
      BYE: goodbye world

- name: Execute command in background by using detach
  containers.podman.podman_container_exec:
    name: detach_container
    command: "cat redhat-release"
    detach: true
"""

RETURN = r"""
stdout:
  type: str
  returned: success
  description:
  - The standard output of the command executed in the container.
stderr:
  type: str
  returned: success
  description:
  - The standard output of the command executed in the container.
rc:
  type: int
  returned: success
  sample: 0
  description:
  - The exit code of the command executed in the container.
exec_id:
  type: str
  returned: success and I(detach=true)
  sample: f99002e34c1087fd1aa08d5027e455bf7c2d6b74f019069acf6462a96ddf2a47
  description:
  - The ID of the exec session.
"""


import shlex
from ansible.module_utils._text import to_text
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.containers.podman.plugins.module_utils.podman.common import (
    run_podman_command,
)


def run_container_exec(module: AnsibleModule) -> dict:
    """
    Execute podman-container-exec for the given options
    """
    exec_with_args = ["container", "exec"]
    # podman_container_exec always returns changed=true
    changed = True
    exec_options = []

    name = module.params["name"]
    argv = module.params["argv"]
    command = module.params["command"]
    detach = module.params["detach"]
    env = module.params["env"]
    privileged = module.params["privileged"]
    tty = module.params["tty"]
    user = module.params["user"]
    workdir = module.params["workdir"]
    executable = module.params["executable"]

    if command is not None:
        argv = shlex.split(command)

    if detach:
        exec_options.append("--detach")

    if env is not None:
        for key, value in env.items():
            if not isinstance(value, str):
                module.fail_json(msg="Specify string value %s on the env field" % (value))

            to_text(value, errors="surrogate_or_strict")
            exec_options += ["--env", "%s=%s" % (key, value)]

    if privileged:
        exec_options.append("--privileged")

    if tty:
        exec_options.append("--tty")

    if user is not None:
        exec_options += ["--user", to_text(user, errors="surrogate_or_strict")]

    if workdir is not None:
        exec_options += ["--workdir", to_text(workdir, errors="surrogate_or_strict")]

    exec_options.append(name)
    exec_options.extend(argv)

    exec_with_args.extend(exec_options)

    rc, stdout, stderr = run_podman_command(
        module=module, executable=executable, args=exec_with_args, ignore_errors=True
    )

    result = {
        "changed": changed,
        "podman_command": exec_options,
        "rc": rc,
        "stdout": stdout,
        "stderr": stderr,
    }

    if detach:
        result["exec_id"] = stdout.replace("\n", "")

    return result


def main():
    argument_spec = {
        "name": {
            "type": "str",
            "required": True,
        },
        "command": {
            "type": "str",
        },
        "argv": {
            "type": "list",
            "elements": "str",
        },
        "detach": {
            "type": "bool",
            "default": False,
        },
        "executable": {
            "type": "str",
            "default": "podman",
        },
        "env": {
            "type": "dict",
        },
        "privileged": {
            "type": "bool",
            "default": False,
        },
        "tty": {
            "type": "bool",
            "default": False,
        },
        "user": {
            "type": "str",
        },
        "workdir": {
            "type": "str",
        },
    }

    module = AnsibleModule(
        argument_spec=argument_spec,
        supports_check_mode=True,
        required_one_of=[("argv", "command")],
    )

    result = run_container_exec(module)
    module.exit_json(**result)


if __name__ == "__main__":
    main()
