#!/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.six import string_types
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, string_types):
                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()
