#!/usr/bin/python
# Copyright: Nokia
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
# pylint: disable=invalid-name
# pylint: disable=wrong-import-position
# pylint: disable=too-many-locals
# pylint: disable=too-many-branches
# pylint: disable=too-many-statements

"""
NetAct CM ansible command module
"""
from __future__ import absolute_import, division, print_function

__metaclass__ = type

DOCUMENTATION = '''
---
module: netact_cm_command

short_description: Manage network configuration data in Nokia Core and Radio networks


description:
    netact_cm_command can be used to run various configuration management operations.
    This module requires that the target hosts have Nokia NetAct network management system installed.
    Module will access the Configurator command line interface in NetAct to upload network configuration to NetAct,
    run configuration export, plan import and configuration provision operations
    To set the scope of the operation, define Distinguished Name (DN) or Working Set (WS) or
    Maintenance Region (MR) as input
options:
    operation:
        description:
            Supported operations allow user to upload actual configuration from the network, to import and
            provision prepared plans, or export reference or actual configuration for planning purposes.
            Provision_Mass_Modification enables provisioning the same parameters to multiple network elements.
            This operation supports modifications only to one object class at a time. With this option
            NetAct Configurator creates and provisions a plan to the network with the given scope and options.
        required: true
        choices:
            - upload
            - provision
            - import
            - export
            - Provision_Mass_Modification
        aliases:
            - op
    opsName:
        description:
            - user specified operation name
        required: false
    DN:
        description:
            Sets the exact scope of the operation in form of a list of managed object
            Distinguished Names (DN) in the network.
            A single DN or a list of DNs can be given (comma separated list without spaces).
            Alternatively, if DN or a list of DNs is not given, working set (WS) or Maintenance Region (MR)
            must be provided as parameter to set the scope of operation.
        required: false

    WS:
        description:
            Sets the scope of the operation to use one or more pre-defined working sets (WS) in NetAct.
            A working set contains network elements selected by user according to defined criteria.
            A single WS name, or multiple WSs can be provided (comma-separated list without spaces).
            Alternatively, if a WS name or a list of WSs is not given, Distinguished Name (DN) or
            Maintenance Region(MR) must be provided as parameter to set the scope of operation.
        required: false
    MR:
        description:
            Sets the scope of the operation to network elements assigned to a Maintenance Region (MR)
            Value can be set as MR IDs including the Maintenance Region Collection (MRC)
            information (for example MRC-FIN1/MR-Hel).
            Multiple MRs can be given (comma-separated list without spaces)
            The value of this parameter is searched through MR IDs under given MRC. If there is no match,
            then it is searched from all MR names.
            Alternatively, if MR ID or a list or MR IDs is not given, Distinguished Name (DN) or Working Set (WS)
            must be provided as parameter to set the scope of operation.
        required: false
    planName:
        description:
            - Specifies a plan name.
        required: false
    typeOption:
        description:
             Specifies the type of the export operation.
        required: false
        choices:
          - plan
          - actual
          - reference
          - template
          - siteTemplate
        aliases:
            - type
    fileFormat:
        description:
            Indicates file format.
        required: false
        choices:
            - RAML2
            - CSV
            - XLSX
    fileName:
        description:
            - Specifies a file name. Valid for Import and Export operations.
        required: false
    inputFile:
        description:
            Specifies full path to plan file location for the import operation.
            This parameter (inputFile) or the fileName parameter must be filled. If both are present then
            the inputFile is used.
        required: false
    createBackupPlan:
        description:
            - Specifies if backup plan generation is enabled.
        required: false
        type: bool
    backupPlanName:
        description:
            - Specifies a backup plan name
        required: false
    verbose:
        description:
            NetAct Configurator will print more info
        required: false
    extra_opts:
        description:
            Extra options to be set for operations. Check Configuration Management > Configuration Management
            Operating Procedures > Command Line Operations in Nokia NetAct user documentation for further
            information for extra options.
        required: false
notes:
    - Check mode is not currently supported
author:
    - Harri Tuominen (@hatuomin)
'''

EXAMPLES = '''
# Pass in a message
- name: Upload
  community.network.netact_cm_command:
    operation: "Upload"
    opsname: 'Uploading_test'
    dn: "PLMN-PLMN/MRBTS-746"
    extra_opts: '-btsContentInUse true'

- name: Provision
  community.network.netact_cm_command:
    operation: "Provision"
    opsname: 'Provision_test'
    dn: "PLMN-PLMN/MRBTS-746"
    planName: 'mySiteTemplate'
    type: 'actual'
    createBackupPlan: true
    backupPlanName: 'myBackupPlanName'

- name: Export and fetching data from target
  community.network.netact_cm_command:
    operation: "Export"
    opsname: 'Export_test'
    planName: 'mySiteTemplate'
    type: 'actual'
    fileName: 'exportTest.xml'
- ansible.builtin.fetch:
    src: /var/opt/nokia/oss/global/racops/export/exportTest.xml
    dest: fetched

- name: Import
  community.network.netact_cm_command:
    operation: "Import"
    opsname: 'Import_test'
    fileFormat: 'CSV'
    type: 'plan'
    fileName: 'myCSVFile'
    planName: 'myPlanName'
    extra_ops: 'enablePolicyPlans true'

# fail the module
- name: Test failure of the module
  community.network.netact_cm_command:
    name: fail me
'''

RETURN = '''
original_message:
    description: The original name param that was passed in
    returned: Command line
    type: str
    sample: '/opt/oss/bin/racclimx.sh -op Upload -opsName Uploading_testi -DN PLMN-PLMN/MRBTS-746'
message:
    description: The output message that the netact_cm_command module generates
    returned: Command output message
    type: str
changed:
    description: data changed
    returned: true if data is changed
    type: bool
'''

from ansible.module_utils.basic import AnsibleModule

racclimx = '/opt/oss/bin/racclimx.sh'


def main():
    """
    Main module where option are handled and command is executed
    :return:
    """
    # define the available arguments/parameters that a user can pass to
    # the module
    module_args = dict(
        operation=dict(type='str', required=True,
                       aliases=['op'],
                       choices=['Upload', 'Provision', 'Import',
                                'Export', 'Provision_Mass_Modification']),
        opsName=dict(type='str', required=False),
        DN=dict(type='str', required=False),
        WS=dict(type='str', required=False),
        MR=dict(type='str', required=False),

        planName=dict(type='str', required=False),
        typeOption=dict(type='str', required=False, aliases=['type'],
                        choices=['plan', 'actual', 'reference', 'template', 'siteTemplate']),
        fileFormat=dict(type='str', required=False, choices=['CSV', 'RAML2', 'XLSX']),
        fileName=dict(type='str', required=False),
        createBackupPlan=dict(type='bool', required=False),
        backupPlanName=dict(type='str', required=False),
        inputFile=dict(type='str', required=False),

        verbose=dict(type='str', required=False),
        extra_opts=dict(type='str', required=False)
    )

    # seed the result dict in the object
    # we primarily care about changed and state
    # change 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='',
        cmd='',
        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:
        result['skipped'] = True
        result['msg'] = 'check mode not (yet) supported for this module'
        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)

    operation = module.params.get('operation')
    if not operation:
        module.fail_json(msg='Operation not defined', **result)

    opsname = module.params.get('opsName')
    dn = module.params.get('DN')
    ws = module.params.get('WS')
    mr = module.params.get('MR')

    planname = module.params.get('planName')
    typeoption = module.params.get('typeOption')
    fileformat = module.params.get('fileFormat')
    filename = module.params.get('fileName')

    createBackupPlan = module.params.get('createBackupPlan')
    backupPlanName = module.params.get('backupPlanName')
    inputfile = module.params.get('inputFile')

    extra_opts = module.params.get('extra_opts')
    verbose = module.params.get('verbose')

    # parameter checks

    command = [racclimx, '-op', operation]

    if opsname:
        command.append('-opsName')
        command.append(opsname)

    if dn:
        command.append('-DN')
        command.append(dn)

    if ws:
        command.append('-WS')
        command.append(ws)

    if mr:
        command.append('-MR')
        command.append(mr)

    if planname:
        command.append('-planName')
        command.append(planname)

    if typeoption:
        command.append('-type')
        command.append(typeoption)

    if fileformat:
        command.append('-fileFormat')
        command.append(fileformat)

    if filename:
        command.append('-fileName')
        command.append(filename)

    if createBackupPlan:
        command.append('-createBackupPlan')
        command.append('true')

    if backupPlanName:
        command.append('-backupPlanName')
        command.append(backupPlanName)

    if inputfile:
        command.append('-inputFile')
        command.append(inputfile)

    if extra_opts:
        command = command + extra_opts.split(" ")

    if verbose:
        if verbose == 'True':
            command.append("-v")

    rc, out, err = module.run_command(command, check_rc=True)
    if rc != 0:
        result['changed'] = False
        module.fail_json(msg=err)
    else:
        result['changed'] = True
        result['original_message'] = out
        result['cmd'] = command
        result['message'] = out

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


if __name__ == '__main__':
    main()
