#!/usr/bin/env python3

import time
from typing import Optional

from serial.serialutil import SerialException

from flipper.app import App
from flipper.storage import FlipperStorage
from flipper.utils.cdc import resolve_port


class Main(App):
    # this is basic use without sub-commands, simply to reboot flipper / power it off, not meant as a full CLI wrapper
    def init(self):
        self.parser.add_argument("-p", "--port", help="CDC Port", default="auto")

        self.subparsers = self.parser.add_subparsers(help="sub-command help")

        self.parser_power_off = self.subparsers.add_parser(
            "power_off", help="Power off command, won't return to CLI"
        )
        self.parser_power_off.set_defaults(func=self.power_off)

        self.parser_reboot = self.subparsers.add_parser(
            "reboot", help="Reboot command help"
        )
        self.parser_reboot.set_defaults(func=self.reboot)

        self.parser_reboot2dfu = self.subparsers.add_parser(
            "reboot2dfu", help="Reboot to DFU, won't return to CLI"
        )
        self.parser_reboot2dfu.set_defaults(func=self.reboot2dfu)

    def _get_flipper(self, retry_count: Optional[int] = 1):
        port = None
        for i in range(retry_count):
            time.sleep(1)
            self.logger.info(
                f"Attempting to find flipper (Attempt {i + 1}/{retry_count})."
            )

            if port := resolve_port(self.logger, self.args.port):
                self.logger.info(f"Found flipper at {port}")
                break

        if not port:
            self.logger.info(f"Failed to find flipper")
            return None

        flipper = FlipperStorage(port)
        for i in range(retry_count):
            try:
                flipper.start()
                self.logger.info("Flipper successfully started.")
                return flipper
            except IOError as e:
                self.logger.info(
                    f"Failed to start flipper (Attempt {i + 1}/{retry_count}): {e}"
                )
                time.sleep(1)

    def power_off(self):
        if not (flipper := self._get_flipper(retry_count=10)):
            return 1

        self.logger.info("Powering off")
        flipper.send("power off" + "\r")
        flipper.stop()
        return 0

    def reboot(self):
        if not (flipper := self._get_flipper(retry_count=10)):
            return 1

        self.logger.info("Rebooting")
        flipper.send("power reboot" + "\r")
        flipper.stop()
        return 0

    def reboot2dfu(self):
        if not (flipper := self._get_flipper(retry_count=10)):
            return 1

        self.logger.info("Rebooting to DFU")
        flipper.send("power reboot2dfu" + "\r")
        flipper.stop()

        return 0


if __name__ == "__main__":
    Main()()
