import argparse
import json
import os
import pprint
import time
from datetime import datetime

import requests

from mficlient import client
from mficlient.client import TIME_FORMAT


class Application:
    def main(self):
        try:
            requests.packages.urllib3.disable_warnings()
        except:  # noqa: E722
            pass
        commands = [x[4:] for x in dir(self) if x.startswith("cmd")]
        command_list = os.linesep + os.linesep.join(commands)

        parser = argparse.ArgumentParser()
        parser.add_argument("command", help="One of: %s" % command_list)
        parser.add_argument("--device", help="Specific device")
        parser.add_argument("--property", help="Show only this property of a device")
        parser.add_argument("--state", help="State to set (on or off)")
        parser.add_argument(
            "--every", type=int, default=0, help="Repeat (interval in seconds)"
        )
        parser.add_argument(
            "--since",
            type=int,
            default=60,
            metavar="SECS",
            help="Show data since SECS seconds ago",
        )
        parser.add_argument(
            "--column-headers",
            default=False,
            action="store_true",
            help="Show CSV column headers",
        )
        parser.add_argument(
            "--json",
            default=False,
            action="store_true",
            help="Output raw JSON for the raw_ commands",
        )
        parser.add_argument(
            "--noverify",
            default=False,
            action="store_true",
            help="Do not verify server SSL certificate",
        )
        args = parser.parse_args()

        if not hasattr(self, "cmd_%s" % args.command):
            print("No such command `%s'" % args.command)
            return 1

        host, port, user, _pass, path, tls = client.get_auth_from_env()
        self._client = client.MFiClient(
            host, user, _pass, port=port, use_tls=tls, verify=not args.noverify
        )

        while True:
            getattr(self, "cmd_%s" % args.command)(args)
            if not args.every:
                break
            time.sleep(args.every)

    def cmd_dump_sensors(self, options):
        devices = self._client.get_devices()

        fmt = "%20s | %20s | %15s | %10s | %s"
        print(fmt % ("Model", "Label", "Tag", "Value", "Extra"))
        print("-" * 78)
        for device in devices:
            for port in device.ports.values():
                print(fmt % (port.model, port.label, port.tag, port.value, port.output))

    def cmd_raw_sensors(self, options):
        data = self._client.get_raw_sensors()
        if options.device:
            data = [x for x in data if x["label"] == options.device]
        if options.json:
            print(json.dumps(data))
        else:
            pprint.pprint(data)

    def cmd_raw_status(self, options):
        data = self._client.get_raw_status()
        if options.json:
            print(json.dumps(data))
        else:
            pprint.pprint(data)

    def cmd_control_device(self, options):
        if not options.device:
            print("Must specify a device")
            return
        if not options.state:
            print("Must specify a state")
            return
        port = self._client.get_port(label=options.device)
        port.control(options.state == "on")

    def cmd_get_data(self, options):
        if not options.device:
            print("Must specify a device")
            return

        devices = self._client.get_devices()
        port = None
        for dev in devices:
            for port in dev.ports.values():
                if port.label == options.device:
                    break
        if port is None:
            print("No such port %s" % options.device)
            return

        headers = list(port.data.keys())
        if options.property:
            if options.property not in headers:
                print("Port has no property `%s`" % options.property)
                return
            headers = [options.property]

        data = [str(port.data[key]) for key in headers]

        if options.column_headers:
            print(",".join(headers))
        print(",".join(data))

    def cmd_sensors_csv(self, options):
        if not options.device:
            print("Must specify a device")
            return
        sensors = self._client.get_raw_sensors()
        keys = [
            "active_pwr",
            "energy_sum",
            "i_rms",
            "v_rms",
            "label",
            "model",
            "output",
            "output_val",
            "pf",
            "port",
            "tag",
            "val",
            "wattHours",
            "wattHoursBase",
        ]
        the_sensor = None
        for sensor in sensors:
            if sensor["label"] == options.device:
                the_sensor = sensor
                break

        if not the_sensor:
            print("No such device `%s'" % options.device)
            return

        rpt_time = datetime.fromtimestamp(sensor["rpt_time"] / 1000)
        try:
            wh_rpt_time = datetime.fromtimestamp(sensor["wh_rpt_time"] / 1000)
        except KeyError:
            wh_rpt_time = ""

        vals = [str(sensor.get(k, "")) for k in keys]
        vals.insert(0, rpt_time.strftime(TIME_FORMAT))
        vals.append(wh_rpt_time and wh_rpt_time.strftime(TIME_FORMAT) or "")
        keys.insert(0, "time")
        keys.append("wh_rpt_time")

        if options.column_headers:
            print(",".join(keys))

        print(",".join(vals))
