#!/usr/bin/python3
"""Implements the seqtool command and its options"""

import subprocess

import asyncio
import click
import json

import seq.cli as seqcli
from seq.lib.exc import SeqConfigError

logChoices = lambda: click.Choice(["DEBUG", "INFO", "WARN", "CRITICAL", "ERROR"])


@click.group()
def main():
    """The Sequencer is a software component developed in the scope of the Instrument
    Control System Framework (ICS FW) as the generic tool for the execution of Observation
    Blocks (OB) and engineering scripts.

    Please use a specific command from the list below."""
    pass


@main.command()
@click.option(
    "--log-level",
    type=logChoices(),
    default="INFO",
    show_default=True,
    help="Will present logs at this level or higher",
)
@click.argument("modules", nargs=-1)
def run(log_level, modules):
    """Starts seq CLI"""
    asyncio.run(seqcli.seqrun(log_level, modules))


@main.command()
@click.option(
    "--log-level",
    type=logChoices(),
    default="INFO",
    show_default=True,
    help="Will present logs at this level or higher",
)
@click.argument("output", nargs=1, type=click.File("wb"))
@click.argument("modules", nargs=-1)
def draw(log_level, output, modules):
    """Draws the graph representation of a Sequencer script
    given in the command line."""
    asyncio.run(seqcli.seqdraw(log_level, output, modules))


@main.command()
@click.option("--address", default=None, help="Sequencer server address [HOST:]PORT")
@click.option(
    "--log-level",
    type=logChoices(),
    default=None,
    help="Will present logs at this level or higher",
)
@click.option("--run", is_flag=True, help="Run the script passed as parameter")
@click.option(
    "--config", default="seqgui_config.yaml", help="sequencer configuration file"
)
@click.option(
    "--gui-log-level",
    type=logChoices(),
    default=None,
    help="Will present GUI logs at this level or higher",
)
@click.argument("script", nargs=-1)
def gui(address, log_level, script, run, config, gui_log_level):
    """Client application for the Sequencer that allows to load OBs and execute
    scripts and monitor their progress."""
    import os

    # We are using qtpy for backward compatibility; it is a simple
    # abstraction layer that supports multiple Qt bindings.
    # We specify through the QT_API environment variable which binding to use.
    if os.environ.get("ELT_RELEASE", "6").startswith("6"):
        os.environ["QT_API"] = "pyside6"
    else:
        os.environ["QT_API"] = "pyside2"

    import seq.gui

    seq.gui.gui_main_app(address, log_level, script, run, config)


@main.command()
@click.option("--config", default=None, help="sequencer configuration file")
def show_config(config):
    from seq.gui import read_config_file, find_config_file

    try:
        config_file = find_config_file(config)
        print("Config File:", config_file)
        d = read_config_file(config)
        print(json.dumps(d, indent=4))
    except SeqConfigError as e:
        print(e.args[0])


@main.command()
@click.option("--address", default="8000", help="Sequencer server address [HOST:]PORT")
@click.option(
    "--log-level",
    type=logChoices(),
    default="INFO",
    show_default=True,
    help="Will present logs at this level or higher",
)
def server(address, log_level):
    """Starts the Sequencer Server, a socket server for the sequencer.

    It listens on the "address" for commands and applies them to its own
    instance of sequencer (seq shell).

    If you need multiple instances of the sequencer server, please
    start them on their own port.
    """
    asyncio.run(seqcli.server(address, log_level))


@main.command()
def client():
    """Starts a text based client"""
    # ignore return values
    proc = subprocess.Popen("nc localhost 8000", shell=True)
    proc.communicate()


@main.command()
@click.option(
    "--topic-id", default="localhost_8000", help="log and state publisher identifier"
)
@click.option(
    "--log-level",
    type=logChoices(),
    default="INFO",
    show_default=True,
    help="Will present logs at this level or higher",
)
@click.option("--use-stdout", default=True)
def shell(topic_id, log_level, use_stdout):
    """Starts a Sequencer Shell; a fully fledged sequencer capable of running
    sequencer scripts and OBs.

    It does not provide network listening capabilities.

    Used internally by `seq server`."""
    asyncio.run(
        seqcli.shell_main(
            topic_id=topic_id,
            log_level=log_level,
            use_stdout=use_stdout,
        )
    )


@main.command()
@click.option("--json/--no-json", default=False)
@click.option(
    "--log-level",
    type=logChoices(),
    default="INFO",
    show_default=True,
    help="Will present logs at this level or higher",
)
@click.option("--log-file", default=None)
@click.option("--pub-id", default=None)
@click.option("--redir", default=True)
def kernel(json, log_file, log_level, pub_id, redir):
    """Starts the Sequencer Kernel; a minimal CLI version of the Sequencer that
    is shell based and logs every feedback response into a log file.

    Used internally by `seq shell`. It does not provide network listening
    capabilities.

    Useful for development of sequences, scripts and OBs.
    """
    asyncio.run(
        seqcli.kmain(
            json_output=json,
#            log_file=log_file,
            log_level=log_level,
            pub_id=pub_id,
        )
    )


@main.command()
@click.option("--port", default=5000, type=int, help="Tino server port")
@click.argument("path", type=click.Path(exists=True))
def tino(path, port):
    """Friend of OTTO"""
    from seq.otto.ottoSim import tino as tino_main

    tino_main(path, port)


if __name__ == "__main__":
    main()
