import datetime
import logging
import re
import subprocess
import time

import docker
from docker.errors import NotFound


DOCKER_SHARED_VOLUME_PATH = '/root/shared_volume'


class DeviceStats(object):

    def __init__(self):
        self.total_battery_capacity_mah = None
        # Est power used (mAh) by the app
        self.estimated_power_usage_mah = None


class AppiumContainer:

    def start_appium_container(self, shared_volume):
        docker_client = docker.from_env()
        try:
            self.container = docker_client.containers.get("appium")
            self.container.restart()
        except NotFound:
            self.container = docker_client.containers.run("appium/appium:local", detach=True, name="appium",
                                                          ports={'4723/tcp': 4723},
                                                          volumes={shared_volume: {
                                                              'bind': DOCKER_SHARED_VOLUME_PATH, 'mode': 'rw'}})
        logging.info("Running Appium container. ID: %s" % self.container.short_id)

    def exec_run(self, cmd):
        return self.container.exec_run(cmd, stdout=True, stderr=True, stdin=True)

    def connect_device(self, device_ip):
        device_address = device_ip + ':5555'
        connected_state = "connected to %s" % device_address

        cmd = self.exec_run(['adb', 'connect', device_address])
        if connected_state in cmd.output.decode("utf-8"):
            logging.info("adb is already connected with the device")
        else:
            logging.info("Connecting the device with adb..")
            # Restart adb on host machine
            subprocess.call(['adb', 'kill-server'])
            input("Connect USB cable to the device and press ENTER..")
            # Reset USB on host machine
            subprocess.call(['adb', 'usb'])
            time.sleep(5)  # wait until adb usb is restarted
            # Set the target device to listen for a TCP/IP connection on port 5555 on host machine
            subprocess.call(['adb', 'tcpip', '5555'])
            # restarting in TCP mode port: 5555
            input("Now, disconnect the USB cable and press ENTER..")
            # Connect to the device in docker container
            self.exec_run(['adb', 'connect', device_address])
            input("Please check your device and allow for USB debugging if necessary. Then press ENTER to continue "
                  "the test..\n")

    def reset_battery_stats(self):
        logging.info("Resetting device stats..")
        self.exec_run(['adb', 'shell', 'dumpsys', 'batterystats', '--reset'])

    def generate_bugreport(self, report_name):
        now = datetime.datetime.now()
        bugreport_name = "bugreport_%s_%s" % (report_name, now.strftime("%Y-%m-%d_%H-%M-%S"))

        print("\nGenerating device report from the test..")
        self.exec_run(['adb', 'bugreport', "/%s/%s" % (DOCKER_SHARED_VOLUME_PATH, bugreport_name)])
        print("Device report saved in the shared volume as %s.zip" % bugreport_name)

    def get_device_stats(self):
        stats = DeviceStats()

        # Find process uid
        uid_line = self.exec_run(['adb', 'shell', 'ps', '|', 'grep', 'im.status.ethereum']).output \
            .decode('utf-8')
        # Match first word which is the uid
        match = re.match(r'(?:^|(?:[.!?]\s))(\w+)', uid_line, re.M | re.I)
        uid = match.group(1).replace('_', '')

        # Battery stats
        batterystats = self.exec_run(['adb', 'shell', 'dumpsys', 'batterystats', 'im.status.ethereum']).output \
            .decode('utf-8').splitlines()
        battery_usage_line = [s for s in batterystats if "Uid %s" % uid in s][0]
        match = re.match(r'.* Uid %s: ([^\s]+)' % uid, battery_usage_line, re.M | re.I)
        stats.estimated_power_usage_mah = float(match.group(1))
        capacity_line = [s for s in batterystats if "Capacity" in s][0]
        match = re.match(r'.* Capacity: (.*), Computed drain: (.*), .*', capacity_line, re.M | re.I)
        stats.total_battery_capacity_mah = float(match.group(1))
        stats.total_computed_drain_mah = float(match.group(2))

        # Wi-Fi stats
        wifi_stats = self.exec_run(['adb', 'shell', 'dumpsys', 'batterystats', 'im.status.ethereum', '|', 'grep',
                                'Wi-Fi total']).output.decode('utf-8')
        stats.wifi_received = wifi_stats.split()[3].replace(',', '')
        stats.wifi_sent = wifi_stats.split()[5]

        # OS stats
        stats.os_version = self.exec_run(['adb', 'shell', 'getprop', 'ro.build.version.release'])\
            .output.decode('utf-8').rstrip("\n")
        stats.device_model = self.exec_run(['adb', 'shell', 'getprop', 'ro.product.model'])\
            .output.decode('utf-8').rstrip("\n")

        return stats

    def stop_container(self):
        self.container.stop()