#!/usr/bin/python3

from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

import os
import sys
import logging
from argparse import Namespace
import pathlib
import traceback

# in the library
mod_path = ''
if os.environ.get('PLAY_ANSIBLE_SRC',''):
    # running from source
    mod_path = os.environ.get('PLAY_ANSIBLE_SRC','')
    mod_path = os.path.join(mod_path, 'src', 'ansible_gentooimgr')
    assert os.path.isdir(mod_path), f"parent {mod_path}"
    assert os.path.isfile(os.path.join(mod_path, '__init__.py')),f"index {mod_path}"
    assert os.path.isdir(os.path.join(mod_path, 'gentooimgr')), f"sub {mod_path}"
    sys.path.append(mod_path)
else:
    # in the library
    mod_path = os.path.dirname(os.path.realpath('__file__'))
    mod_path = os.path.join(mod_path, 'src', 'ansible_gentooimgr')
    assert os.path.isdir(mod_path), f"parent {mod_path}"
    assert os.path.isfile(os.path.join(mod_path, '__init__.py')),f"index {mod_path}"
    assert os.path.isdir(os.path.join(mod_path, 'gentooimgr')), f"sub {mod_path}"
    sys.path.append(mod_path)
try:
    import gentooimgr
except Exception as e:
    sys.stderr.write(f"{mod_path} {sys.path} {traceback.print_exc()}")
    raise
import ansible

DOCUMENTATION = rf'''
---
module: gentooimgr

short_description: Gentoo Image Builder for Cloud and Turnkey ISO installers


version_added: "1.0.0"

description:
* This project enables easy access to building ``systemd`` or ``openrc`` -based images.
* Performs automatic download AND verification of the linux iso, stage3 tarball and portage.
* Caches the iso and stage3 .txt files for at most a day before redownloading and rechecking for new files
* Sane and readable cli commands to build, run and test.
* Step system to enable user to continue off at the same place if a step fails
* No heavy packages like rust included ** TODO

options:
    action:
        description: The action to be run by the image builder
        choices:
            - build
            - run
            - status
            - install
            - chroot
            - unchroot
            - command
            - shrink
            - kernel
        required: true
        # clean test
    config:
        default: cloud.json
        description: init configuration file or or base.json or cloud.json
        required: false
    loglevel:
        default: {logging.INFO}
        description: python logging level <= 50, INFO=20
        required: false
    threads:
        default: 1
        description: Number of threads to use
        required: false
    profile:
        default: openrc
        description: The init system
        choices:
            - openrc
            - systemd
        required: false
    kernel_dir:
        default: /usr/src/linux
        description: Where kernel is specified. By default uses the active linux kernel
        required: false
    portage:
        description: Extract the specified portage tarball onto the filesystem
        required: false
    stage3:
        description: Extract the specified stage3 package onto the filesystema
        required: false
    action_args:
        default: []
        description: Arguments for some of the actions - UNUSED!
        required: false
    temporary_dir:
        description: Path to temporary directory for downloading files (20G)
        required: false
    qcow:
        description: Path to file to serve as the base image
        required: false

# Specify this value according to your collection
# in format of namespace.collection.doc_fragment_name
# extends_documentation_fragment:
#     - my_namespace.my_collection.my_doc_fragment_name

author:
    - Your Name (@yourGitHubHandle)
'''

#[-y DAYS]
#                  [-d DOWNLOAD_DIR]
# [-f]
#                  [--format FORMAT]

EXAMPLES = r'''
# Pass in a message
- name: Test with a message
  my_namespace.my_collection.my_test:
    name: hello world

# pass in a message and have changed true
- name: Test with a message and changed output
  my_namespace.my_collection.my_test:
    name: hello world
    new: true

# fail the module
- name: Test failure of the module
  my_namespace.my_collection.my_test:
    name: fail me
'''

RETURN = r'''
# These are examples of possible return values, and in general should use other names for return values.
message:
    description: The output message that the test module generates.
    type: str
    returned: always
    sample: 'goodbye'
'''

from ansible.module_utils.basic import AnsibleModule


def run_module():
    # define available arguments/parameters a user can pass to the module
    #? default config from __file__ ?
    if mod_path and os.path.isdir(mod_path):
        def_config = os.path.join(mod_path, 'configs', 'base.json')
    else:
        # WARN:
        def_config = 'base.json'
    module_args = dict(
        action=dict(type='str', required=True),
        loglevel=dict(type='int', required=False, default=logging.INFO),
        threads=dict(type='int', required=False, default=1),
        # Module error: required and default are mutually exclusive for config
        config=dict(type='path', default=def_config),
        profile=dict(type='str', required=False),
        kernel_dir=dict(type='path', required=False),
        portage=dict(type='path', required=False),
        stage3=dict(type='path', required=False),
        temporary_dir=dict(type='path', required=False, default=pathlib.Path(os.getcwd())),
        download_dir=dict(type='path', required=False, default=pathlib.Path(os.getcwd())),
        qcow=dict(type='path', required=False),
    )

    # seed the result dict in the object
    # we primarily care about changed and state
    # changed is if this module effectively modified the target
    # state will include any data that you want your module to pass back
    # for consumption, for example, in a subsequent task
    result = dict(
        changed=False,
        original_message='',
        message=''
    )

    # the AnsibleModule object will be our abstraction working with Ansible
    # this includes instantiation, a couple of common attr would be the
    # args/params passed to the execution, as well as if the module
    # supports check mode
    module = AnsibleModule(
        argument_spec=module_args,
        supports_check_mode=True
    )

    # if the user is working with this module in only check mode we do not
    # want to make any changes to the environment, just return the current
    # state with no modifications
    if module.check_mode:
        module.exit_json(**result)

    # manipulate or modify the state as needed (this is going to be the
    # part where your module will do what it needs to do)
    # if module.params.get('thirsty'):

    oargs = Namespace(**module.params)
    # during the execution of the module, if there is an exception or a
    # conditional state that effectively causes a failure, run
    # AnsibleModule.fail_json() to pass in the message and the result
    result['original_message'] = ""
    try:
        from gentooimgr.__main__ import main
        retval = main(oargs)
        # should be 0
        # is stdout already in result? how can it be?
    except Exception as e:
        result['message'] = str(e)
        result['original_message'] = f"{traceback.print_exc()}"
        module.fail_json(msg=f'Exception {e.__class__}', **result)
    else:
        result['message'] = str(retval)

    # use whatever logic you need to determine whether or not this module
    # made any modifications to your target
    # build run test chroot unchroot status clean kernel shrink
    if oargs.action in ['status', '']:
        result['changed'] = False
    else:
        result['changed'] = True

    # 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()

