from .. import enums
from ..errors.vm import VirtualMachineDatacenterNotFoundError


class VmApiMixin:
    def vm_datacenter_get(self, *, vdc_id, **kwargs):
        """
        This method allows you to retrieve a datacenter's information by vdc_id.

        :param int vdc_id: VM Datacenter identifier.

        :return: On success, returns an object with the following properties:
        :rtype: dict

        **Properties**

        vdc_agent_hostname
            Agent hostname/IP address.
        vdc_agent_password
            Agent password.
        vdc_agent_username
            Agent username.
        vdc_date_added
            Timestamp of when VDC was added to NETLAB+.
        vdc_date_tested
            Timestamp of when VDC was last tested.
        vdc_last_test_status
            Status of last VDC test.
        vdc_id
            VM Datacenter identifier.
        vdc_name
            VM Datacenter name.
        vdt_type
            VM Datacenter type.
        vdt_name
            VM Datacenter type name.
        """

        method = "vm.datacenter.get"
        return self.call(method, vdc_id=vdc_id, **kwargs)

    def vm_datacenter_find(self, *, vdc_name, **kwargs):
        """
        This method allows you to find a datacenter's **vdc_id** by the datacenter name.

        :param str vdc_name: VM Datacenter name.

        :return: On success, returns vdc_id. If there is no VDC matching, returns None.
        :rtype: int
        """

        method = "vm.datacenter.get"
        try:
            return self.call(method, vdc_name=vdc_name, **kwargs)['vdc_id']
        except VirtualMachineDatacenterNotFoundError:
            return None

    def vm_datacenter_list(self, **kwargs):
        """
        This method allows you to retrieve all datacenters' information.

        :return: A list of objects with the following properties:
        :rtype: list

        **Properties**

        vdc_agent_hostname
            Agent hostname/IP address.
        vdc_agent_password
            Agent password.
        vdc_agent_username
            Agent username.
        vdc_date_added
            Timestamp of when VDC was added to NETLAB+.
        vdc_date_tested
            Timestamp of when VDC was last tested.
        vdc_last_test_status
            Status of last VDC test.
        vdc_id
            VM Datacenter identifier.
        vdc_name
            VM Datacenter name.
        vdt_type
            VM Datacenter type.
        vdt_name
            VM Datacenter type name.
        """

        method = "vm.datacenter.list"
        return self.call(method, **kwargs)

    def vm_datacenter_test(self, *, vdc_id, **kwargs):
        """
        This method allows you to call a task to test communication to datacenter.

        :param int vdc_id: VM Datacenter identifier.

        :return: On success returns 'PASSED', otherwise returns 'FAILED'.
        :rtype: 'PASSED' or 'FAILED'
        """

        method = "vm.datacenter.test.task"
        return self.call(method, vdc_id=vdc_id, **kwargs)

    def vm_host_get(self, *, vh_id, **kwargs):
        """
        This method allows you to retrieve a virtual host information.

        :param int vh_id: Virtual host identifier.

        :return: On success, returns an object with the following properties:
        :rtype: dict

        **Properties**

        vdc_id
            Agent hostname/IP address.
        vdc_name
            VM Datacenter name.
        vdt_type
            VM Datacenter type.
        vdt_name
            VM Datacenter type name.
        vh_bios_date
            Timestamp of BIOS creation date.
        vh_bios_version
            BIOS version installed.
        vh_com_path
            Virtual host communication path.
        vh_cpu_cores
            Total count of CPU cores on virtual host.
        vh_cpu_count
            Total count of physical CPUs on virtual host.
        vh_cpu_mhz
            Speed in MHz of CPU.
        vh_cpu_model
            CPU model identification.
        vh_cpu_threads
            Number of threads CPUs can handle.
        vh_date_added
            Timestamp of virtual host added to NETLAB+.
        vh_date_modified
            Timestamp of virtual host information has been modified.
        vh_date_tested
            Timestamp of virtual host test communication.
        vh_id
            Virtual host identifier.
        vh_inside_ipv4_addr
            Inside interface ipv4 address.
        vh_inside_vswitch_0
            Virtual host inside vSwitch.
        vh_last_test_status
            Status of last virtual host test communication.
        vh_memory_mb
            Total RAM in MB of virtual host.
        vh_name
            Virtual host hostname.
        vh_online
            Virtual host is online.
        vh_os_build
            Operating system build number.
        vh_os_description
            Operating system description.
        vh_os_name
            Operating system name.
        vh_os_type
            Operating system type.
        vh_os_vendor
            Operating system vender.
        vh_os_version
            Operating system version.
        vh_outside_ipv4_addr
            Outside interface ipv4 address.
        vh_pra_enabled
            Proactive resource awareness is enabled.
        vh_pra_max_cpu
            Max number of CPUs for PRA.
        vh_pra_max_mem_mb
            Max amount of RAM in MB for PRA.
        vh_pra_max_vm
            Max amount of virtual machines for PRA.
        vh_sys_model
            System model.
        vh_sys_service_tag
            System service tag.
        vh_sys_vendor
            System vendor.
        vh_uuid
            Virtual host unique global identifier.
        """

        method = "vm.host.get"
        return self.call(method, vh_id=vh_id, **kwargs)

    def vm_host_find(self, *, vh_name, **kwargs):
        """
        This method allows you to find a virtual host's **vh_id** by the virtual host name.

        :param str vh_name: Virtual Host name.

        :return: On success, returns vh_id. If there is no matching Virtual Host, returns None.
        :rtype: int
        """

        method = "vm.host.list"
        hosts = self.call(method, **kwargs)
        for host in hosts:
            if host.get('vh_name') == vh_name:
                return host['vh_id']
        else:
            return None

    def vm_host_list(self, *, vdc_id=0, **kwargs):
        """
        This method allows you to retrieve a list of virtual hosts information.

        :param str vdc_id: VM Datacenter identifier. If not specified, will return from all datacenters.

        :return: Returns a list of objects with the following properties:
        :rtype: dict

        **Properties**

        vdc_id
            Agent hostname/IP address.
        vdc_name
            VM Datacenter name.
        vdt_type
            VM Datacenter type.
        vdt_name
            VM Datacenter type name.
        vh_bios_date
            Timestamp of BIOS creation date.
        vh_bios_version
            BIOS version installed.
        vh_com_path
            Virtual host communication path.
        vh_cpu_cores
            Total count of CPU cores on virtual host.
        vh_cpu_count
            Total count of physical CPUs on virtual host.
        vh_cpu_mhz
            Speed in MHz of CPU.
        vh_cpu_model
            CPU model identification.
        vh_cpu_threads
            Number of threads CPUs can handle.
        vh_date_added
            Timestamp of virtual host added to NETLAB+.
        vh_date_modified
            Timestamp of virtual host information has been modified.
        vh_date_tested
            Timestamp of virtual host test communication.
        vh_id
            Virtual host identifier.
        vh_inside_ipv4_addr
            Inside interface ipv4 address.
        vh_inside_vswitch_0
            Virtual host inside vSwitch.
        vh_last_test_status
            Status of last virtual host test communication.
        vh_memory_mb
            Total RAM in MB of virtual host.
        vh_name
            Virtual host hostname.
        vh_online
            Virtual host is online.
        vh_os_build
            Operating system build number.
        vh_os_description
            Operating system description.
        vh_os_name
            Operating system name.
        vh_os_type
            Operating system type.
        vh_os_vendor
            Operating system vender.
        vh_os_version
            Operating system version.
        vh_outside_ipv4_addr
            Outside interface ipv4 address.
        vh_pra_enabled
            Proactive resource awareness is enabled.
        vh_pra_max_cpu
            Max number of CPUs for PRA.
        vh_pra_max_mem_mb
            Max amount of RAM in MB for PRA.
        vh_pra_max_vm
            Max amount of virtual machines for PRA.
        vh_sys_model
            System model.
        vh_sys_service_tag
            System service tag.
        vh_sys_vendor
            System vendor.
        vh_uuid
            Virtual host unique global identifier.
        """

        method = "vm.host.list"
        return self.call(method, vdc_id=vdc_id, **kwargs)

    def vm_inventory_add(self, *, vdc_id, vm_uuid, vm_name, vm_path=None, vm_alloc_mem_mb, vm_alloc_cpu_n, vhg_id=None,
                         vh_id=None, vm_role=enums.VirtualMachineRole.NORMAL, vm_comments=None, vm_vendor_os_id=None,
                         vm_vendor_os_name=None, vm_netlab_os_id=None, vm_parent_id=None, vm_parent_snapname=None,
                         **kwargs):
        """
        Add virtual machines to NETLAB+ inventory.

        :param int vdc_id: VM Datacenter identifier.
        :param int vhg_id: Virtual host group identifier.
        :param int vh_id: Virtual host identifier.
        :param str vm_uuid: Virtual machine unique identifier.
        :param str vm_name: Virtual machine name.
        :param str vm_path: Virtual machine path on datastore.
        :param netlab.enums.VirtualMachineRole vm_role: Virtual machine role in NETLAB+ inventory.
        :param int vm_alloc_mem_mb: Total amount of allocated RAM.
        :param int vm_alloc_cpu_n: Total amount of allocated CPUs.
        :param str vm_comments: Virtual machine comments from VMX.
        :param str vm_vendor_os_id: Vendor operating system identifier.
        :param str vm_vendor_os_name: Vendor operating system name.
        :param str vm_netlab_os_id: NETLAB+ match to vm_vendor_os_id.
        :param int vm_parent_id: Virtual machine parent identifier, if VM is a link clone.
        :param str vm_parent_snapname: Virtual machine parent snapname, if VM is a link clone.

        :return: Returns a list of object with the following properties:
        :rtype: list[dict]

        **properties**

        vm_id
            Virtual machine identifier.
        """

        method = 'vm.inventory.add'
        return self.call(method, vdc_id=vdc_id, vm_uuid=vm_uuid, vm_name=vm_name, vm_path=vm_path,
                         vm_alloc_mem_mb=vm_alloc_mem_mb, vm_alloc_cpu_n=vm_alloc_cpu_n, vhg_id=vhg_id, vh_id=vh_id,
                         vm_role=vm_role, vm_comments=vm_comments, vm_vendor_os_id=vm_vendor_os_id,
                         vm_vendor_os_name=vm_vendor_os_name, vm_netlab_os_id=vm_netlab_os_id,
                         vm_parent_id=vm_parent_id, vm_parent_snapname=vm_parent_snapname, **kwargs)

    def vm_inventory_get(self, *, vm_id, **kwargs):
        """
        This method allows you to retrieve one or more virtual machines from NETLAB+ inventory.

        :param int vm_id: Virtual machine identifier.

        :return: Returns an object with the following properties:
        :rtype: dict

        **Properties**

        pc_id
            Remote pc identifier.
        pc_label
            Remote pc label.
        pc_os_id
            NETLAB+ operating system identifier.
        pc_os_name
            NETLAB+ operating system name.
        pc_pod_id
            If attached to a pod, pod identifier.
        pc_vm_id
            Virtual machine identifier.
        pod_name
            Pod name.
        vdc_id
            Virtual datacenter identifier.
        vdc_name
            Virtual datacenter name.
        vh_id
            Virtual host identifier.
        vh_name
            Virtual host name.
        vhg_id
            Virtual host group identifier.
        vhg_name
            Virtual host group name.
        vm_alloc_cpu_n
            Total amount of allocated CPUs.
        vm_alloc_mem_mb
            Total amount of allocated RAM.
        vm_child_count
            Total count of children VMs.
        vm_comments
            Virtual machine comments from VMX.
        vm_date_added
            Timestamp of virtual machine added to NETLAB+ inventory.
        vm_id
            Virtual machine identifier.
        vm_name
            Virtual machine name.
        vm_netlab_os_id
            NETLAB+ match to vm_vendor_os_id.
        vm_parent_id
            Virtual machine parent identifier, if VM is a link clone.
        vm_parent_name
            Virtual machine parent name.
        vm_parent_role
            Parent virtual machine role.
        vm_parent_snapname
            Virtual machine parent snapname, if VM is a link clone.
        vm_path
            Virtual machine path on datastore.
        vm_power_state
            Virtual machine power state.
        vm_role
            Virtual machine role in NETLAB+ inventory.
        vm_snapshot
            This is what the VM reverts to when the pod is reset. You can take multiple snapshots with the same name,
            without having to update this field. Update this field with a call to
            :meth:`~netlab.api.PodApiMixin.pod_pc_update`
        vm_uuid
            Virtual machine unique identifier.
        vm_vendor_os_id
            Vendor operating system identifier.
        vm_vendor_os_name
            Vendor operating system name.

        """
        method = "vm.inventory.get"
        return self.call(method, vm_id=vm_id, **kwargs)

    def vm_inventory_list(self, *, vdc_id=None, roles=None, attached=None, **kwargs):
        """
        This method allows you to list the virtual machines from NETLAB+ inventory.

        :param int vdc_id: VM Datacenter identifier.
        :param list roles: Filter by specified roles.
        :param int attached: List virtual machines attached to a pod.


        :return: Returns an object with the following properties:
        :rtype: dict

        **Properties**

        pc_id
            Remote pc identifier.
        pc_label
            Remote pc label.
        pc_os_id
            NETLAB+ operating system identifier.
        pc_os_name
            NETLAB+ operating system name.
        pc_pod_id
            If attached to a pod, pod identifier.
        pc_vm_id
            Virtual machine identifier.
        pod_name
            Pod name.
        vdc_id
            Virtual datacenter identifier.
        vdc_name
            Virtual datacenter name.
        vh_id
            Virtual host identifier.
        vh_name
            Virtual host name.
        vhg_id
            Virtual host group identifier.
        vhg_name
            Virtual host group name.
        vm_alloc_cpu_n
            Total amount of allocated CPUs.
        vm_alloc_mem_mb
            Total amount of allocated RAM.
        vm_child_count
            Total count of children VMs.
        vm_comments
            Virtual machine comments from VMX.
        vm_date_added
            Timestamp of virtual machine added to NETLAB+ inventory.
        vm_id
            Virtual machine identifier.
        vm_name
            Virtual machine name.
        vm_netlab_os_id
            NETLAB+ match to vm_vendor_os_id.
        vm_parent_id
            Virtual machine parent identifier, if VM is a link clone.
        vm_parent_name
            Virtual machine parent name.
        vm_parent_role
            Parent virtual machine role.
        vm_parent_snapname
            Virtual machine parent snapname, if VM is a link clone.
        vm_path
            Virtual machine path on datastore.
        vm_power_state
            Virtual machine power state.
        vm_role
            Virtual machine role in NETLAB+ inventory.
        vm_snapshot
            This is what the VM reverts to when the pod is reset. You can take multiple snapshots with the same name,
            without having to update this field. Update this field with a call to
            :meth:`~netlab.api.PodApiMixin.pod_pc_update`
        vm_uuid
            Virtual machine unique identifier.
        vm_vendor_os_id
            Vendor operating system identifier.
        vm_vendor_os_name
            Vendor operating system name.
        """
        method = "vm.inventory.get"
        params = {}

        if vdc_id:
            params['vdc_id'] = vdc_id
        if roles:
            params['roles'] = roles
        if attached is not None:
            params['attached'] = attached

        params.update(kwargs)
        return self.call(method, **params)

    def vm_snapshot_add(self, *, vm_id=None, pc_id=None, snapshot_name, dump_memory=False, sync=False,
                        description=None, **kwargs):
        """
        Method to call a task to add snapshot to virtual machine.

        :param int vm_id: Virtual datacenter identifier.
        :param int pc_id: Remote pc identifier.
        :param str snapshot_name: Name of snapshot to take.
        :param bool dump_memory: Dump memory files.
        :param bool sync: Sync files.
        :param str description: Snapshot description.

        :return: The snapshot completed successfully.
        :rtype: 'OK'
        """

        method = "vm.snapshot.add.task"
        return self.call(method, vm_id=vm_id, pc_id=pc_id, snapshot_name=snapshot_name, dump_memory=dump_memory,
                         sync=sync, description=description, **kwargs)

    def vm_snapshot_edit(self, *, vm_id=None, pc_id=None, snapshot_id=None, new_snapshot_name=None,
                         new_snapshot_description=None, **kwargs):
        """
        Method to call a task to edit a snapshot.

        :param int vm_id: Virtual datacenter identifier.
        :param int pc_id: Remote pc identifier.
        :param int snapshot_id: Snapshot identifier.
        :param int new_snapshot_name: New name of snapshot to take.
        :param str new_snapshot_description: New description of snapshot.

        :return: The edit completed successfully.
        :rtype: 'OK'
        """
        method = "vm.snapshot.edit.task"
        return self.call(method, vm_id=vm_id, pc_id=pc_id, snapshot_id=snapshot_id,
                         new_snapshot_name=new_snapshot_name, new_snapshot_description=new_snapshot_description,
                         **kwargs)

    def vm_snapshot_get_list(self, *, vm_id=None, pc_id=None, **kwargs):
        """
        Method to call a task to retrieve a list of snapshots.

        :param int vm_id: Virtual datacenter identifier.
        :param int pc_id: Remote pc identifier.

        :return: Returns a dict with the following properties:
        :rtype: dict

        **Properties**

        current_snapshot
            The current snapshot. See *Snapshot properties* for more info.
        snapshot_list
            A list of all snapshots. See *Snapshot properties* for more info.

        **Snapshot properties**

        power_state
            The state of the snapshot. :py:class:`PowerState`
        name
            The snapshot name.
        description
            The snapshot description.
        parent_id
            The id of the snapshot parent.
        id
            The snapshot id.
        mo_ref
            The unique identifier of the managed object in vSphere.
        """
        method = "vm.snapshot.get.list.task"
        return self.call(method, vm_id=vm_id, pc_id=pc_id, **kwargs)

    def vm_snapshot_get_tree(self, *, vm_id=None, pc_id=None, **kwargs):
        """
        Method to call a task to retrieve snapshot tree.

        :param int vm_id: Virtual datacenter identifier.
        :param int pc_id: Remote pc identifier.

        :return: Returns a dict with the following properties:
        :rtype: dict

        **Properties**

        current_snapshot
            The current snapshot. See *Snapshot properties* for more info.
        snapshot_list
            A list of all snapshots. See *Snapshot properties* for more info.

        **Snapshot properties**

        power_state
            The state of the snapshot. :py:class:`PowerState`
        name
            The snapshot name.
        description
            The snapshot description.
        id
            The snapshot id.
        mo_ref
            The unique identifier of the managed object in vSphere.
        """
        method = "vm.snapshot.get.tree.task"
        return self.call(method, vm_id=vm_id, pc_id=pc_id, **kwargs)

    def vm_snapshot_remove(self, *, vm_id=None, pc_id=None, snapshot_name=None, snapshot_id=None, remove_children=None,
                           remove_all_snapshots=None, **kwargs):
        """
        Method to call a task to remove snapshot from virtual machine.

        :param int vm_id: Virtual datacenter identifier.
        :param int pc_id: Remote pc identifier.
        :param str snapshot_name: Name of snapshot to take.
        :param int snapshot_id: Snapshot identifier.
        :param bool remove_children: Remove children snapshots.
        :param bool remove_all_snapshots: Remove all snapshots of virtual machine.

        :return: The removal completed successfully.
        :rtype: 'OK'
        """
        method = "vm.snapshot.remove.task"
        return self.call(
            method, vm_id=vm_id, pc_id=pc_id, snapshot_name=snapshot_name, snapshot_id=snapshot_id,
            remove_children=remove_children, remove_all_snapshots=remove_all_snapshots, **kwargs)

    def vm_snapshot_revert(self, *, vm_id=None, pc_id=None, snapshot_name=None, snapshot_id=None, **kwargs):
        """
        Method to call a task to revert to snapshot from virtual machine.

        :param int vm_id: Virtual datacenter identifier.
        :param int pc_id: Remote pc identifier.
        :param str snapshot_name: Name of snapshot to take.
        :param int snapshot_id: Snapshot identifier.

        :return: The revert completed successfully.
        :rtype: 'OK'
        """
        method = "vm.snapshot.revert.task"
        return self.call(
            method, vm_id=vm_id, pc_id=pc_id, snapshot_name=snapshot_name, snapshot_id=snapshot_id, **kwargs)
