#!/usr/bin/python
#
# Copyright (c) 2021 Ross Bender (@l3ender)
#
# 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_webappvnetconnection
version_added: "1.8.0"
short_description: Manage web app virtual network connection
description:
    - Add, remove, or update the virtual network connection for a web app.
options:
    name:
        description:
            - Name of the web app.
        required: true
        type: str
    resource_group:
        description:
            - Resource group of the web app.
        required: true
        type: str
    state:
        description:
            - State of the virtual network connection. Use C(present) to create or update and C(absent) to delete.
        type: str
        default: present
        choices:
            - absent
            - present
    vnet_name:
        description:
            - Name of the virtual network. Required if adding or updating.
        type: str
    subnet:
        description:
            - Name of the virtual network's subnet. Required if adding or updating.
        type: str
    vnet_resource_group:
        description:
            - Name of the resource group for the virtual network. Defaults to main C(resource_group) value.
        type: str

extends_documentation_fragment:
    - azure.azcollection.azure

author:
    - Ross Bender (@l3ender)
'''

EXAMPLES = '''
    - name: Configure web app with virtual network
      azure.azcollection.azure_rm_webappvnetconnection:
        name: "MyWebapp"
        resource_group: "MyResourceGroup"
        vnet_name: "MyVnetName"
        subnet: "MySubnetName"

    - name: Configure web app with virtual network in different resource group
      azure.azcollection.azure_rm_webappvnetconnection:
        name: "MyWebapp"
        resource_group: "MyResourceGroup"
        vnet_name: "MyVnetName"
        subnet: "MySubnetName"
        vnet_resource_group: "MyOtherResourceGroup"

    - name: Delete web app virtual network
      azure.azcollection.azure_rm_webappvnetconnection:
        name: "MyWebapp"
        resource_group: "MyResourceGroup"
        state: "absent"
'''

RETURN = '''
connection:
    description:
        - The web app's virtual network connection.
    returned: always
    type: complex
    contains:
        id:
            description:
                - ID of the web app virtual network connection.
            returned: always
            type: str
            sample: /subscriptions/xxx-xxx/resourceGroups/myResourceGroup/providers/Microsoft.Web/sites/myWebApp/virtualNetworkConnections/yyy-yyy_subnet
        name:
            description:
                - Name of the web app virtual network connection.
            returned: always
            type: str
            sample: yyy-yyy_subnet
        subnet_name:
            description:
               - Name of the subnet connected to the web app.
            returned: always
            type: str
            sample: mySubnet
        vnet_name:
            description:
               - Name of the virtual network connected to the web app.
            returned: always
            type: str
            sample: myVnet
        vnet_resource_group:
            description:
               - Name of the resource group the virtual network is in.
            returned: always
            type: str
            sample: myResourceGroup
        vnet_resource_id:
            description:
               - ID of the virtual network/subnet connected to the web app.
            returned: always
            type: str
            sample: /subscriptions/xxx-xxx/resourceGroups/myResourceGroup/providers/Microsoft.Network/virtualNetworks/myVnet/subnets/mySubnet
'''

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

try:
    from azure.mgmt.web.models import SwiftVirtualNetwork
except Exception:
    # This is handled in azure_rm_common
    pass


class AzureRMWebAppVnetConnection(AzureRMModuleBase):

    def __init__(self):

        self.module_arg_spec = dict(
            name=dict(type='str', required=True),
            resource_group=dict(type='str', required=True),
            state=dict(type='str', default='present', choices=['present', 'absent']),
            vnet_name=dict(type='str'),
            subnet=dict(type='str'),
            vnet_resource_group=dict(type='str'),
        )

        self.results = dict(
            changed=False,
            connection=dict(),
        )

        self.state = None
        self.name = None
        self.resource_group = None
        self.vnet_name = None
        self.subnet = None
        self.vnet_resource_group = None

        super(AzureRMWebAppVnetConnection, self).__init__(self.module_arg_spec,
                                                          supports_check_mode=True,
                                                          supports_tags=False)

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

        changed = False
        vnet = self.get_vnet_connection()
        if vnet:
            self.results['connection'] = self.set_results(vnet)

        if self.state == 'absent' and vnet:
            changed = True
            if not self.check_mode:
                self.log('Deleting vnet connection for webapp {0}'.format(self.name))
                self.delete_vnet_connection()
                self.results['connection'] = dict()
        elif self.state == 'present':
            self.vnet_resource_group = self.vnet_resource_group or self.resource_group

            if not vnet:
                self.log('Adding vnet connection for webapp {0}'.format(self.name))
                changed = True
            else:
                subnet_detail = self.get_subnet_detail(vnet.vnet_resource_id)
                if (subnet_detail['resource_group'] != self.vnet_resource_group
                        or subnet_detail['vnet_name'] != self.vnet_name
                        or subnet_detail['subnet_name'] != self.subnet):
                    self.log('Detected change in vnet connection for webapp {0}'.format(self.name))
                    changed = True

            if changed:
                if not self.check_mode:
                    self.log('Updating vnet connection for webapp {0}'.format(self.name))
                    subnet = self.get_subnet()
                    param = SwiftVirtualNetwork(subnet_resource_id=subnet.id)
                    self.create_or_update_vnet_connection(param)
                    vnet = self.get_vnet_connection()
                    self.results['connection'] = self.set_results(vnet)

        self.results['changed'] = changed
        return self.results

    def get_vnet_connection(self):
        connections = self.list_vnet_connections()
        for connection in connections:
            if connection.is_swift:
                return connection

        return None

    def list_vnet_connections(self):
        try:
            return self.web_client.web_apps.list_vnet_connections(resource_group_name=self.resource_group, name=self.name)
        except Exception as exc:
            self.fail("Error getting webapp vnet connections {0} (rg={1}) - {2}".format(self.name, self.resource_group, str(exc)))

    def delete_vnet_connection(self):
        try:
            return self.web_client.web_apps.delete_swift_virtual_network(resource_group_name=self.resource_group, name=self.name)
        except Exception as exc:
            self.fail("Error deleting webapp vnet connection {0} (rg={1}) - {3}".format(self.name, self.resource_group, str(exc)))

    def create_or_update_vnet_connection(self, vnet):
        try:
            return self.web_client.web_apps.create_or_update_swift_virtual_network_connection_with_check(
                resource_group_name=self.resource_group, name=self.name, connection_envelope=vnet)
        except Exception as exc:
            self.fail("Error creating/updating webapp vnet connection {0} (vnet={1}, rg={2}) - {3}".format(
                self.name, self.vnet_name, self.resource_group, str(exc)))

    def get_subnet(self):
        try:
            return self.network_client.subnets.get(resource_group_name=self.vnet_resource_group, virtual_network_name=self.vnet_name, subnet_name=self.subnet)
        except Exception as exc:
            self.fail("Error getting subnet {0} in vnet={1} (rg={2}) - {3}".format(self.subnet, self.vnet_name, self.vnet_resource_group, str(exc)))

    def set_results(self, vnet):
        vnet_dict = vnet.as_dict()

        output = dict()
        output['id'] = vnet_dict['id']
        output['name'] = vnet_dict['name']
        subnet_id = vnet_dict.get('subnet_resource_id', vnet_dict.get('vnet_resource_id'))
        output['vnet_resource_id'] = subnet_id
        subnet_detail = self.get_subnet_detail(subnet_id)
        output['vnet_resource_group'] = subnet_detail['resource_group']
        output['vnet_name'] = subnet_detail['vnet_name']
        output['subnet_name'] = subnet_detail['subnet_name']

        return output


def main():
    AzureRMWebAppVnetConnection()


if __name__ == '__main__':
    main()
