#!/usr/bin/python
# Copyright (c) 2017-present Alibaba Group Holding Limited. <xiaozhu36>
# 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

ANSIBLE_METADATA = {'metadata_version': '1.1',
                    'status': ['preview'],
                    'supported_by': 'community'}

DOCUMENTATION = """
---
module: ali_ram_role
short_description: Create, Delete, Update Ram Role in Alibaba Cloud.
description:
    - Create, Delete, Update Role in Alibaba Cloud.
    - An unique ali_ram_role module is determined by parameters role_name. 
options:        
  state:
    description:
      - If I(state=present), role will be created.
      - If I(state=present), and assume_role_policy_document exists, role will be updated.
      - If I(state=absent), role will be removed.
    choices: ['present', 'absent']
    default: 'present'
    type: str
  role_name:
    description:
      - The name of the RAM role. The specified name can be up to 64 characters in length. Format(^[a-zA-Z0-9\. @\-]+$)
      - One of I(role_name) and I(role_id) must be specified when operate existing role.
    aliases: ['name']
    type: str
  role_id:
    description:
      - The id of the RAM role.
      - One of I(role_name) and I(role_id) must be specified when operate existing role.
    aliases: ['id']
    type: str
  assume_role_policy_document:
    description:
      - The policy text that specifies one or more entities entrusted to assume the RAM role. 
        The trusted entity can be an Alibaba Cloud account, Alibaba Cloud service, or identity provider (IdP).
      - Required when C(state=present)
    type: str
    aliases: ['policy']
  description:
    description:
      - The description of the RAM role. The description can be up to 1,024 characters in length.
    type: str
requirements:
    - "python >= 3.6"
    - "footmark >= 1.17.0"
extends_documentation_fragment:
    - alibaba.alicloud.alicloud
author:
  - "He Guimin (@xiaozhu36)"
"""

EXAMPLES = """
# Note: These examples do not set authentication details, see the Alibaba Cloud Guide for details.
- name: Changed. Create a role
  alibaba.alicloud.ali_ram_role:
    role_name: ansible
    policy: '{"Statement": [{"Action": "sts:AssumeRole","Effect": "Allow","Principal": {"Service": ["rds.aliyuncs.com"]}}],"Version": "1"}'
    description: create for ansible

- name: Changed. Update role
  alibaba.alicloud.ali_ram_role:
    role_name: ansible
    policy: '{"Statement": [{"Action": "sts:AssumeRole","Effect": "Allow","Principal": {"Service": ["ecs.aliyuncs.com"]}}],"Version": "1"}'

- name: Changed. Delete role
  alibaba.alicloud.ali_ram_role:
    state: absent
    role_name: ansible
"""

RETURN = '''
role:
    description: Returns an array of complex objects as described below.
    returned: always
    type: complex
    contains:
        arn:
            description: The Alibaba Cloud Resource Name (ARN) of the RAM role.
            returned: always
            type: str
            sample: acs:ram::123456789012****:role/ECSAdmin
        assume_role_policy_document:
            description: The policy text that specifies one or more entities entrusted to assume the RAM role.
            returned: always
            type: str
            sample: '{ "Statement": [ { "Action": "sts:AssumeRole", "Effect": "Allow", "Principal": { "RAM": "acs:ram::123456789012****:root" } } ], "Version": "1" }'
        create_date:
            description: The date and time when the RAM role was created.
            returned: always
            type: str
            sample: '2015-01-23T12:33:18Z'
        description:
            description: The description of the RAM role.
            returned: always
            type: str
            sample: ECS administrator
        role_id:
            description: The ID of the RAM role.
            returned: always
            type: str
            sample: 901234567890****
        role_name:
            description: The name of the RAM role.
            returned: always
            type: str
            sample: ECSAdmin
'''

from ansible.module_utils.basic import AnsibleModule
from ansible_collections.alibaba.alicloud.plugins.module_utils.alicloud_ecs import ecs_argument_spec, ram_connect

HAS_FOOTMARK = False

try:
    from footmark.exception import RAMResponseError
    HAS_FOOTMARK = True
except ImportError:
    HAS_FOOTMARK = False


def role_exists(module, ram_conn, role_name, role_id):
    try:
        role = None
        filters = {'MaxItems': 1000}
        for r in ram_conn.list_roles(**filters):
            if role_name and r.read()['role_name'] != role_name:
                continue
            if role_id and r.read()['role_id'] != role_id:
                continue
            role = r
        return role
    except Exception as e:
        module.fail_json(msg="Failed to describe Roles: {0}".format(e))


def main():
    argument_spec = ecs_argument_spec()
    argument_spec.update(dict(
        state=dict(default='present', choices=['present', 'absent']),
        role_name=dict(type='str', aliases=['name']),
        role_id=dict(type='str', aliases=['id']),
        assume_role_policy_document=dict(type='str', aliases=['policy']),
        description=dict(type='str')
    ))

    module = AnsibleModule(argument_spec=argument_spec)

    if HAS_FOOTMARK is False:
        module.fail_json(msg='footmark required for this module.')

    ram_conn = ram_connect(module)

    # Get values of variable
    state = module.params['state']
    role_name = module.params['role_name']
    assume_role_policy_document = module.params['assume_role_policy_document']
    role_id = module.params['role_id']
    changed = False

    # Check if role exists
    role = role_exists(module, ram_conn, role_name, role_id)

    if state == 'absent':
        if not role:
            module.exit_json(changed=changed, role={})
        try:
            module.exit_json(changed=role.delete(), role={})
        except RAMResponseError as ex:
            module.fail_json(msg='Unable to delete role {0}, error: {1}'.format(role_name, ex))

    if not role:
        try:
            role = ram_conn.create_role(**module.params)
            module.exit_json(changed=True, role=role.read())
        except RAMResponseError as e:
            module.fail_json(msg='Unable to create role, error: {0}'.format(e))

    if assume_role_policy_document:
        try:
            changed = role.update_policy(policy=assume_role_policy_document)
            module.exit_json(changed=changed, role=role.get().read())
        except RAMResponseError as e:
            module.fail_json(msg='Unable to update role policy, error: {0}'.format(e))


if __name__ == '__main__':
    main()
