#!/usr/bin/python
#
# Copyright: Ansible Project
# 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: onyx_mlag_ipl
author: "Samer Deeb (@samerd)"
short_description: Manage IPL (inter-peer link) on Mellanox ONYX network devices
description:
  - This module provides declarative management of IPL (inter-peer link)
    management on Mellanox ONYX network devices.
notes:
  - Tested on ONYX 3.6.4000
options:
  name:
    description:
      - Name of the interface (port-channel) IPL should be configured on.
    required: true
  vlan_interface:
    description:
      - Name of the IPL vlan interface.
  state:
    description:
      - IPL state.
    default: present
    choices: ['present', 'absent']
  peer_address:
    description:
      - IPL peer IP address.
'''

EXAMPLES = """
- name: Run configure ipl
  onyx_mlag_ipl:
    name: Po1
    vlan_interface: Vlan 322
    state: present
    peer_address: 192.168.7.1

- name: Run remove ipl
  onyx_mlag_ipl:
    name: Po1
    state: absent
"""

RETURN = """
commands:
  description: The list of configuration mode commands to send to the device.
  returned: always
  type: list
  sample:
    - interface port-channel 1 ipl 1
    - interface vlan 1024 ipl 1 peer-address 10.10.10.10
"""
import re

from ansible.module_utils.basic import AnsibleModule

from ansible_collections.community.network.plugins.module_utils.network.onyx.onyx import BaseOnyxModule
from ansible_collections.community.network.plugins.module_utils.network.onyx.onyx import show_cmd


class OnyxMlagIplModule(BaseOnyxModule):
    VLAN_IF_REGEX = re.compile(r'^Vlan \d+')

    @classmethod
    def _get_element_spec(cls):
        return dict(
            name=dict(required=True),
            state=dict(default='present',
                       choices=['present', 'absent']),
            peer_address=dict(),
            vlan_interface=dict(),
        )

    def init_module(self):
        """ module initialization
        """
        element_spec = self._get_element_spec()
        argument_spec = dict()
        argument_spec.update(element_spec)
        self._module = AnsibleModule(
            argument_spec=argument_spec,
            supports_check_mode=True)

    def get_required_config(self):
        module_params = self._module.params
        self._required_config = dict(
            name=module_params['name'],
            state=module_params['state'],
            peer_address=module_params['peer_address'],
            vlan_interface=module_params['vlan_interface'])
        self.validate_param_values(self._required_config)

    def _update_mlag_data(self, mlag_data):
        if not mlag_data:
            return
        mlag_summary = mlag_data.get("MLAG IPLs Summary", {})
        ipl_id = "1"
        ipl_list = mlag_summary.get(ipl_id)
        if ipl_list:
            ipl_data = ipl_list[0]
            vlan_id = ipl_data.get("Vlan Interface")
            vlan_interface = ""
            if vlan_id != "N/A":
                vlan_interface = "Vlan %s" % vlan_id
            peer_address = ipl_data.get("Peer IP address")
            name = ipl_data.get("Group Port-Channel")
            self._current_config = dict(
                name=name,
                peer_address=peer_address,
                vlan_interface=vlan_interface)

    def _show_mlag_data(self):
        cmd = "show mlag"
        return show_cmd(self._module, cmd, json_fmt=True, fail_on_error=False)

    def load_current_config(self):
        # called in base class in run function
        self._current_config = dict()
        mlag_data = self._show_mlag_data()
        self._update_mlag_data(mlag_data)

    def _get_interface_cmd_name(self, if_name):
        if if_name.startswith('Po'):
            return if_name.replace("Po", "port-channel ")
        self._module.fail_json(
            msg='invalid interface name: %s' % if_name)

    def _generate_port_channel_command(self, if_name, enable):
        if_cmd_name = self._get_interface_cmd_name(if_name)
        if enable:
            ipl_cmd = 'ipl 1'
        else:
            ipl_cmd = "no ipl 1"
        cmd = "interface %s %s" % (if_cmd_name, ipl_cmd)
        return cmd

    def _generate_vlan_if_command(self, if_name, enable, peer_address):
        if_cmd_name = if_name.lower()
        if enable:
            ipl_cmd = 'ipl 1 peer-address %s' % peer_address
        else:
            ipl_cmd = "no ipl 1"
        cmd = "interface %s %s" % (if_cmd_name, ipl_cmd)
        return cmd

    def _generate_no_ipl_commands(self):
        curr_interface = self._current_config.get('name')
        req_interface = self._required_config.get('name')
        if curr_interface == req_interface:
            cmd = self._generate_port_channel_command(
                req_interface, enable=False)
            self._commands.append(cmd)

    def _generate_ipl_commands(self):
        curr_interface = self._current_config.get('name')
        req_interface = self._required_config.get('name')
        if curr_interface != req_interface:
            if curr_interface and curr_interface != 'N/A':
                cmd = self._generate_port_channel_command(
                    curr_interface, enable=False)
                self._commands.append(cmd)
            cmd = self._generate_port_channel_command(
                req_interface, enable=True)
            self._commands.append(cmd)
        curr_vlan = self._current_config.get('vlan_interface')
        req_vlan = self._required_config.get('vlan_interface')
        add_peer = False
        if curr_vlan != req_vlan:
            add_peer = True
            if curr_vlan:
                cmd = self._generate_vlan_if_command(curr_vlan, enable=False,
                                                     peer_address=None)
                self._commands.append(cmd)
        curr_peer = self._current_config.get('peer_address')
        req_peer = self._required_config.get('peer_address')
        if req_peer != curr_peer:
            add_peer = True
        if add_peer and req_peer:
            cmd = self._generate_vlan_if_command(req_vlan, enable=True,
                                                 peer_address=req_peer)
            self._commands.append(cmd)

    def generate_commands(self):
        state = self._required_config['state']
        if state == 'absent':
            self._generate_no_ipl_commands()
        else:
            self._generate_ipl_commands()


def main():
    """ main entry point for module execution
    """
    OnyxMlagIplModule.main()


if __name__ == '__main__':
    main()
