#!/usr/bin/python
#
# Copyright (c) 2017 Obezimnaka Boms, <t-ozboms@microsoft.com>
#
# 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

DOCUMENTATION = '''
---
module: azure_rm_dnsrecordset_info

version_added: "0.1.2"

short_description: Get DNS Record Set facts

description:
    - Get facts for a specific DNS Record Set in a Zone, or a specific type in all Zones or in one Zone etc.

options:
    relative_name:
        description:
            - Only show results for a Record Set.
        type: str
    resource_group:
        description:
            - Limit results by resource group. Required when filtering by name or type.
        type: str
    zone_name:
        description:
            - Limit results by zones. Required when filtering by name or type.
        type: str
    record_type:
        description:
            - Limit record sets by record type.
        type: str
    top:
        description:
            - Limit the maximum number of record sets to return.
        type: int

extends_documentation_fragment:
    - azure.azcollection.azure
    - azure.azcollection.azure_tags

author:
    - Ozi Boms (@ozboms)

'''

EXAMPLES = '''
- name: Get facts for one Record Set
  azure_rm_dnsrecordset_info:
    resource_group: myResourceGroup
    zone_name: example.com
    relative_name: server10
    record_type: A
- name: Get facts for all Type A Record Sets in a Zone
  azure_rm_dnsrecordset_info:
    resource_group: myResourceGroup
    zone_name: example.com
    record_type: A
- name: Get all record sets in one zone
  azure_rm_dnsrecordset_info:
    resource_group: myResourceGroup
    zone_name: example.com
'''

RETURN = '''
azure_dnsrecordset:
    description:
        - List of record set dicts.
    returned: always
    type: list
    example: [
    {
        "etag": "60ac0480-44dd-4881-a2ed-680d20b3978e",
        "id": "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/myResourceGroup/providers/Microsoft.Network/dnszones/newzone.com/A/servera",
        "name": "servera",
        "properties": {
            "ARecords": [
                {
                    "ipv4Address": "10.4.5.7"
                },
                {
                    "ipv4Address": "2.4.5.8"
                }
            ],
            "TTL": 12900
        },
        "type": "Microsoft.Network/dnszones/A"
    }]
dnsrecordsets:
    description:
        - List of record set dicts, which shares the same hierarchy as M(azure.azcollection.azure_rm_dnsrecordset) module's parameter.
    returned: always
    type: complex
    contains:
        id:
            description:
                - ID of the dns recordset.
            type: str
            sample: "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/myResourceGroup/providers/Microsoft.Network/dnszones/newzone.
                     com/A/servera"
        relative_name:
            description:
                - Name of the dns recordset.
            type: str
            sample: servera
        record_type:
            description:
                - The type of the record set.
                - Can be C(A), C(AAAA), C(CNAME), C(MX), C(NS), C(SRV), C(TXT), C(PTR).
            type: str
            sample: A
        time_to_live:
            description:
                - Time to live of the record set in seconds.
            type: int
            sample: 12900
        records:
            description:
                - List of records depending on the type of recordset.
            type: dict
            sample: [
                        {
                            "ipv4Address": "10.4.5.7"
                        },
                        {
                            "ipv4Address": "2.4.5.8"
                        }
                    ]
        provisioning_state:
            description:
                - Provision state of the resource.
            type: str
            sample: Successed
        fqdn:
            description:
                - Fully qualified domain name of the record set.
            type: str
            sample: www.newzone.com
        target_resource:
            description:
                - A reference to an azure resource from where the dns resource value is taken.
            type: dict
            returned: always
            sample: {'id': /subscriptions/xxx-xxx/resourceGroups/testRG/providers/Microsoft.Network/publicIPAddresses/pip01'}
'''

from ansible_collections.azure.azcollection.plugins.module_utils.azure_rm_common import AzureRMModuleBase

try:
    from azure.core.exceptions import ResourceNotFoundError
except Exception:
    # This is handled in azure_rm_common
    pass

AZURE_OBJECT_CLASS = 'RecordSet'


RECORDSET_VALUE_MAP = dict(
    A='a_records',
    AAAA='aaaa_records',
    CNAME='cname_record',
    MX='mx_records',
    NS='ns_records',
    PTR='ptr_records',
    SRV='srv_records',
    TXT='txt_records',
    SOA='soa_record',
    CAA='caa_records'
    # FUTURE: add missing record types from https://github.com/Azure/azure-sdk-for-python/blob/master/azure-mgmt-dns/azure/mgmt/dns/models/record_set.py
)


class AzureRMRecordSetInfo(AzureRMModuleBase):

    def __init__(self):

        # define user inputs into argument
        self.module_arg_spec = dict(
            relative_name=dict(type='str'),
            resource_group=dict(type='str'),
            zone_name=dict(type='str'),
            record_type=dict(type='str'),
            top=dict(type='int')
        )

        # store the results of the module operation
        self.results = dict(
            changed=False,
        )

        self.relative_name = None
        self.resource_group = None
        self.zone_name = None
        self.record_type = None
        self.top = None

        super(AzureRMRecordSetInfo, self).__init__(self.module_arg_spec, supports_check_mode=True)

    def exec_module(self, **kwargs):

        for key in self.module_arg_spec:
            setattr(self, key, kwargs[key])

        if not self.top or self.top <= 0:
            self.top = None

        # create conditionals to catch errors when calling record facts
        if self.relative_name and not self.resource_group:
            self.fail("Parameter error: resource group required when filtering by name or record type.")
        if self.relative_name and not self.zone_name:
            self.fail("Parameter error: DNS Zone required when filtering by name or record type.")

        results = []
        # list the conditions for what to return based on input
        if self.relative_name is not None:
            # if there is a name listed, they want only facts about that specific Record Set itself
            results = self.get_item()
        elif self.record_type:
            # else, they just want all the record sets of a specific type
            results = self.list_type()
        elif self.zone_name:
            # if there is a zone name listed, then they want all the record sets in a zone
            results = self.list_zone()

        self.results['dnsrecordsets'] = self.curated_list(results)
        return self.results

    def get_item(self):
        self.log('Get properties for {0}'.format(self.relative_name))
        item = None
        results = []

        # try to get information for specific Record Set
        try:
            item = self.dns_client.record_sets.get(self.resource_group, self.zone_name, self.relative_name, self.record_type)
        except ResourceNotFoundError:
            results = []
            pass
        else:
            results = [item]
        return results

    def list_type(self):
        self.log('Lists the record sets of a specified type in a DNS zone')
        try:
            response = self.dns_client.record_sets.list_by_type(self.resource_group, self.zone_name, self.record_type, top=self.top)
        except Exception as exc:
            self.fail("Failed to list for record type {0} - {1}".format(self.record_type, str(exc)))

        results = []
        for item in response:
            results.append(item)
        return results

    def list_zone(self):
        self.log('Lists all record sets in a DNS zone')
        try:
            response = self.dns_client.record_sets.list_by_dns_zone(self.resource_group, self.zone_name, top=self.top)
        except Exception as exc:
            self.fail("Failed to list for zone {0} - {1}".format(self.zone_name, str(exc)))

        results = []
        for item in response:
            results.append(item)
        return results

    def serialize_list(self, raws):
        return [self.serialize_obj(item, AZURE_OBJECT_CLASS) for item in raws] if raws else []

    def curated_list(self, raws):
        return [self.record_to_dict(item) for item in raws] if raws else []

    def record_to_dict(self, record):
        record_type = record.type[len('Microsoft.Network/dnszones/'):]
        records = getattr(record, RECORDSET_VALUE_MAP.get(record_type))
        if records:
            if not isinstance(records, list):
                records = [records]
        else:
            records = []
        return dict(
            id=record.id,
            relative_name=record.name,
            record_type=record_type,
            records=[x.as_dict() for x in records],
            time_to_live=record.ttl,
            fqdn=record.fqdn,
            provisioning_state=record.provisioning_state,
            metadata=record.metadata,
            target_resource=dict(id=record.target_resource.id) if record.target_resource.id else None
        )


def main():
    AzureRMRecordSetInfo()


if __name__ == '__main__':
    main()
