# Copyright 2020 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import logging


from autotest_lib.client.common_lib import error
from autotest_lib.client.common_lib import utils
from autotest_lib.server import autotest
from autotest_lib.server import test
from autotest_lib.server.hosts import factory


class power_LW(test.test):
    """Wrapper test around a client test for power lab."""
    version = 1

    SERVO_V4_ETH_VENDOR = '0bda'
    SERVO_V4_ETH_PRODUCT = '8153'
    WIFI_SSID = 'powertest_ap'

    def _get_wlan_ip(self, host):
        """Connect to wifi and return wlan ip address."""
        wlan_ip = host.get_wlan_ip()
        if wlan_ip:
            return wlan_ip

        if not host.connect_to_wifi(self.WIFI_SSID):
            logging.info('Script to connect to wifi is probably missing.'
                         'Run dummy_Pass as a workaround to install it.')
            autotest_client = autotest.Autotest(host)
            autotest_client.run_test('dummy_Pass')
            if not host.connect_to_wifi(self.WIFI_SSID):
                raise error.TestError('Can not connect to wifi.')

        wlan_ip = host.get_wlan_ip()
        if not wlan_ip:
            raise error.TestError('Can not find wlan ip.')
        return wlan_ip

    def _get_wlan_host(self, host, machine):
        """Return CrosHost object that use wifi."""
        wlan_ip = self._get_wlan_ip(host)
        if machine['hostname'] == wlan_ip:
            return host

        hostname = wlan_ip
        if utils.host_is_in_power_lab(machine['hostname']):
            hostname = utils.get_power_lab_wlan_hostname(machine['hostname'])

        machine['hostname'] = hostname
        return factory.create_host(machine)

    def _stop_ethernet(self, host):
        """Find and unbind servo v4 usb ethernet."""
        # Stop check_ethernet.hook to reconnect the usb device
        host.run('stop recover_duts')
        eth_usb = host.find_usb_devices(
            self.SERVO_V4_ETH_VENDOR, self.SERVO_V4_ETH_PRODUCT)
        if len(eth_usb) == 1 and eth_usb[0] and host.get_wlan_ip():
            host.unbind_usb_device(eth_usb[0])

    def run_once(self, host, test, args, machine):
        """Prepare DUT for power test then run the client test.

        The DUT will
        - Switch from ethernet connection to wifi.
        - Unbind Servo v4 USB ethernet device.
        - Set EC to force discharge during the client test.

        @param host: CrosHost object representing the DUT.
        @param test: testname
        @param args: arguments of the test in a dict.
        @param machine: machine dict of the host.
        """
        wlan_host = self._get_wlan_host(host, machine)
        if wlan_host != host:
            self._stop_ethernet(host)

        args['force_discharge'] = True
        args['tag'] = args.get('tag', 'PLW')

        autotest_client = autotest.Autotest(wlan_host)
        autotest_client.run_test(test, **args)

        # Restore USB ethernet device.
        wlan_host.reboot()
