#!/usr/bin/python
#
# Copyright Tristan Le Guern <tleguern at bouledef.eu>
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later


DOCUMENTATION = r"""
module: proxmox_user_info
short_description: Retrieve information about one or more Proxmox VE users
description:
  - Retrieve information about one or more Proxmox VE users.
options:
  domain:
    description:
      - Restrict results to a specific authentication realm.
    aliases: ['realm']
    type: str
  user:
    description:
      - Restrict results to a specific user.
    aliases: ['name']
    type: str
  userid:
    description:
      - Restrict results to a specific user ID, which is a concatenation of a user and domain parts.
    type: str
author: Tristan Le Guern (@tleguern)
extends_documentation_fragment:
  - community.proxmox.proxmox.actiongroup_proxmox
  - community.proxmox.proxmox.documentation
  - community.proxmox.attributes
  - community.proxmox.attributes.info_module
"""

EXAMPLES = r"""
- name: List existing users
  community.proxmox.proxmox_user_info:
    api_host: helldorado
    api_user: root@pam
    api_password: "{{ password | default(omit) }}"
    api_token_id: "{{ token_id | default(omit) }}"
    api_token_secret: "{{ token_secret | default(omit) }}"
  register: proxmox_users

- name: List existing users in the pve authentication realm
  community.proxmox.proxmox_user_info:
    api_host: helldorado
    api_user: root@pam
    api_password: "{{ password | default(omit) }}"
    api_token_id: "{{ token_id | default(omit) }}"
    api_token_secret: "{{ token_secret | default(omit) }}"
    domain: pve
  register: proxmox_users_pve

- name: Retrieve information about admin@pve
  community.proxmox.proxmox_user_info:
    api_host: helldorado
    api_user: root@pam
    api_password: "{{ password | default(omit) }}"
    api_token_id: "{{ token_id | default(omit) }}"
    api_token_secret: "{{ token_secret | default(omit) }}"
    userid: admin@pve
  register: proxmox_user_admin

- name: Alternative way to retrieve information about admin@pve
  community.proxmox.proxmox_user_info:
    api_host: helldorado
    api_user: root@pam
    api_password: "{{ password | default(omit) }}"
    api_token_id: "{{ token_id | default(omit) }}"
    api_token_secret: "{{ token_secret | default(omit) }}"
    user: admin
    domain: pve
  register: proxmox_user_admin
"""


RETURN = r"""
proxmox_users:
  description: List of users.
  returned: always, but can be empty
  type: list
  elements: dict
  contains:
    comment:
      description: Short description of the user.
      returned: on success
      type: str
    domain:
      description: User's authentication realm, also the right part of the user ID.
      returned: on success
      type: str
    email:
      description: User's email address.
      returned: on success
      type: str
    enabled:
      description: User's account state.
      returned: on success
      type: bool
    expire:
      description: Expiration date in seconds since EPOCH. Zero means no expiration.
      returned: on success
      type: int
    firstname:
      description: User's first name.
      returned: on success
      type: str
    groups:
      description: List of groups which the user is a member of.
      returned: on success
      type: list
      elements: str
    keys:
      description: User's two factor authentication keys.
      returned: on success
      type: str
    lastname:
      description: User's last name.
      returned: on success
      type: str
    tokens:
      description: List of API tokens associated to the user.
      returned: on success
      type: list
      elements: dict
      contains:
        comment:
          description: Short description of the token.
          returned: on success
          type: str
        expire:
          description: Expiration date in seconds since EPOCH. Zero means no expiration.
          returned: on success
          type: int
        privsep:
          description: Describe if the API token is further restricted with ACLs or is fully privileged.
          returned: on success
          type: bool
        tokenid:
          description: Token name.
          returned: on success
          type: str
    user:
      description: User's login name, also the left part of the user ID.
      returned: on success
      type: str
    userid:
      description: Proxmox user ID, represented as user@realm.
      returned: on success
      type: str
"""


import traceback

from ansible.module_utils.basic import AnsibleModule

from ansible_collections.community.proxmox.plugins.module_utils.proxmox import (
    ProxmoxAnsible,
    proxmox_auth_argument_spec,
    proxmox_to_ansible_bool,
)

try:
    import proxmoxer
except ImportError:
    PROXMOXER_LIBRARY = False
    PROXMOXER_LIBRARY_IMPORT_ERROR = traceback.format_exc()
else:
    PROXMOXER_LIBRARY = True
    PROXMOXER_LIBRARY_IMPORT_ERROR = None


class ProxmoxUserInfoAnsible(ProxmoxAnsible):
    def get_user(self, userid):
        try:
            user = self.proxmox_api.access.users.get(userid)
        except proxmoxer.core.ResourceException:
            result = dict(changed=False)
            result["proxmox_users"] = []
            self.module.exit_json(**result)
        except Exception as e:
            self.module.fail_json(msg=f"Getting specific user '{userid}' failed: {e}")
        user["userid"] = userid
        return ProxmoxUser(user)

    def get_users(self, domain=None):
        users = self.proxmox_api.access.users.get(full=1)
        users = [ProxmoxUser(user) for user in users]
        if domain:
            return [user for user in users if user.user["domain"] == domain]
        return users


class ProxmoxUser:
    def __init__(self, user):
        self.user = dict()
        # Data representation is not the same depending on API calls
        for k, v in user.items():
            if k == "enable":
                self.user["enabled"] = proxmox_to_ansible_bool(user["enable"])
            elif k == "userid":
                self.user["user"] = user["userid"].split("@")[0]
                self.user["domain"] = user["userid"].split("@")[1]
                self.user[k] = v
            elif k in ["groups", "tokens"] and (v == "" or v is None):
                self.user[k] = []
            elif k == "groups" and isinstance(v, str):
                self.user["groups"] = v.split(",")
            elif k == "tokens" and isinstance(v, list):
                for token in v:
                    if "privsep" in token:
                        token["privsep"] = proxmox_to_ansible_bool(token["privsep"])
                self.user["tokens"] = v
            elif k == "tokens" and isinstance(v, dict):
                self.user["tokens"] = list()
                for tokenid, tokenvalues in v.items():
                    t = tokenvalues
                    t["tokenid"] = tokenid
                    if "privsep" in tokenvalues:
                        t["privsep"] = proxmox_to_ansible_bool(tokenvalues["privsep"])
                    self.user["tokens"].append(t)
            else:
                self.user[k] = v


def proxmox_user_info_argument_spec():
    return dict(
        domain=dict(type="str", aliases=["realm"]),
        user=dict(type="str", aliases=["name"]),
        userid=dict(type="str"),
    )


def main():
    module_args = proxmox_auth_argument_spec()
    user_info_args = proxmox_user_info_argument_spec()
    module_args.update(user_info_args)

    module = AnsibleModule(
        argument_spec=module_args,
        required_one_of=[("api_password", "api_token_id")],
        required_together=[("api_token_id", "api_token_secret")],
        mutually_exclusive=[("user", "userid"), ("domain", "userid")],
        supports_check_mode=True,
    )
    result = dict(changed=False)

    proxmox = ProxmoxUserInfoAnsible(module)
    domain = module.params["domain"]
    user = module.params["user"]
    if user and domain:
        userid = user + "@" + domain
    else:
        userid = module.params["userid"]

    if userid:
        users = [proxmox.get_user(userid=userid)]
    else:
        users = proxmox.get_users(domain=domain)
    result["proxmox_users"] = [user.user for user in users]

    module.exit_json(**result)


if __name__ == "__main__":
    main()
