#!/usr/bin/python

# 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

import os
import traceback
from ansible.module_utils.basic import AnsibleModule, missing_required_lib

IMPORT_ERR = None
try:
#    import _argon2_xffi_bindings
    import pykeepass as keepass
except ImportError:
    IMPORT_ERR = traceback.format_exc()

DOCUMENTATION = r'''
---
module: ansible-keepassxc

short_description: Module to read credentials from KeePassXC

version_added: "0.0.1"

description: Module to read credentials from KeePassXC

options:
    database:
        description: Path to database file
        required: true
        type: str
    password:
        description: Database Password
        required: true
        type: str
    keyfile:
        description: Path to key file
        required: false
        type: str
    entry:
        description: Entry name for the attribute to fetch
        required: true
        type: str
    group:
        decription: Group name that the Entry belongs to
        required: false
        type: str

author:
    - Jeremy Lumley (@jlumley)
'''

EXAMPLES = r'''
# Fetch the credentials for the server_1 entry in any group
- name: Fetch server_1 credentials
  jlumley.jlumley.ansible-keepassxc:
    database: "/secrets/db.kdbx"
    password: "s3cure_p4550rd"
    entry: "server_1"

# Fetch the reddit entry in the social group
- name: Fetching reddit credentials
  jlumley.jlumley.ansible-keepassxc:
    database: "/secrets/db.kdbx"
    password: "sup3r_s3cure_p4550rd"
    entry: "reddit"
    group: "social"

# Fetch a custom strig attribute from the github entry
- name: Fetch Github API Token
  jlumley.jlumley.ansible-keepassxc:
    database: "/secrets/db.kdbx"
    password: "d0pe_s3cure_p4550rd"
    keyfile: "/secrets/top_secret_key"
    entry: "github"
    group: "development"

'''

RETURN = r'''
# Return values
username:
    description: Username of entry if present
    type: str
    returned: always
    sample: 's3cr3t_us3r'
password:
    description: Password of entry if present
    type: str
    returned: always
    sample: 's3cr3t_p455word'
url:
    description: Url of entry if present
    type: str
    returned: always
    sample: 'http://reddit.com'
custom_fields:
    description: dictionary containing all custom fields
    type: dict
    returned: always
    sample: False
no_log:
    description: suppress logging of password
    type: bool
    returned: never
    sample: False
'''

def run_module():
    # define available arguments/parameters a user can pass to the module
    module_args = dict(
        database    = dict(type='str', required=True),
        password    = dict(type='str', required=False,
                           default=os.environ.get('ANSIBLE_KEEPASSXC_PASSWORD')),
        keyfile     = dict(type='str', required=False, default=None),
        entry       = dict(type='str', required=True),
        group       = dict(type='str', required=False),
        no_log     = dict(type='bool', required=False, default=False),
    )

    # seed the result dict in the object
    result = dict(
        changed=False,
        username='',
        password='',
        url='',
        custom_fields={}
    )

    # Currently no support for a check_mode this maybe added later if
    # functionality to modify the database is added later
    module = AnsibleModule(
        argument_spec=module_args,
        supports_check_mode=False,
    )

    if IMPORT_ERR:
        module.fail_json(
            msg=missing_required_lib("pykeepass"),
            exception=IMPORT_ERR
        )

    # unlock local keepass database
    try:
        kp = keepass.PyKeePass(
            module.params['database'],
            password=module.params['password'],
            keyfile=module.params['keyfile'])
    except keepass.exceptions.CredentialsError:
        module.fail_json(msg='Invalid Credentials')

    # find entry
    entry = kp.find_entries(
        title=module.params['entry'],
        group=module.params['group']
    )

    # fail is entry is not present
    if not entry:
        module.fail_json(msg=f"Unable to find entry: {module.params['entry']}")

    else:
        entry = entry[0]
        custom_field_keys = entry._get_string_field_keys(exclude_reserved=True)
        custom_fields = dict()
        for key in custom_field_keys:
            custom_fields[key] = entry.get_custom_property(key)
        result = dict (
            changed=False,
            username=entry.username,
            password=entry.password,
            url=entry.url,
            custom_fields=custom_fields
        )

    # in the event of a successful module execution, you will want to
    # simple AnsibleModule.exit_json(), passing the key/value results
    module.exit_json(**result)


def main():
    run_module()


if __name__ == '__main__':
    main()