import asyncio
import copy
import logging
import logging.config
import shutil
import sys
import tempfile
from pathlib import Path
from typing import Any

import click

from .. import debugger

LOGGING = {
    "version": 1,
    "root": {
        "handlers": ["rich"],
        "level": "DEBUG",
    },
    "formatters": {
        "brief": {"format": "%(message)s"},
        "default": {"format": "%(asctime)s %(levelname)-8s %(module)-15s %(message)s"},
    },
    "handlers": {
        "rich": {"class": "rich.logging.RichHandler", "formatter": "brief"},
    },
}


log = logging.getLogger()


async def run_install_wormhole():
    proc = await asyncio.create_subprocess_exec(sys.executable, "-m", "pip", "install", "magic-wormhole")

    await proc.communicate()


async def run_wormhole(wormhole_cmd, file_name):
    proc = await asyncio.create_subprocess_exec(
        wormhole_cmd,
        "send",
        file_name,
    )

    await proc.communicate()


def find_wormhole():
    wormhole_cmd = shutil.which("wormhole")
    if wormhole_cmd is not None:
        return wormhole_cmd
    wormhole_cmd = shutil.which(str(Path(sys.executable).parent.joinpath("wormhole")))
    if wormhole_cmd is not None:
        return wormhole_cmd


@click.command()
@click.option("--system", default="default", help="NETLAB+ system to communicate with.")
@click.option("--output-file", "output_file", type=click.Path())
@click.option("--wormhole", is_flag=True, help="Send logs over magic-wormhole.")
@click.option("--install-wormhole", is_flag=True, help="Install magic-wormhole if needed.")
@click.pass_context
def debug(ctx, system, output_file, wormhole, install_wormhole):
    """
    This will collect debugging data that will be useful for us to assist you.

    It will:

    \b
    - Collect system data
    - Collect config and where it came from
    - Run openssl s_client
    - Connect to a netlab and collects debug traffic
    - Collect `system_status_get`
    - Collect full traceback of all errors
    - Optional: output to file
    - Optional: install magic wormhole
    - Optional: send the results over magic wormhole

    # Using magic wormhole

    https://magic-wormhole.readthedocs.io/en/latest/

    If you cannot easily collect the debug output, you can use the --wormhole
    flag to easily get the debug output at a different computer. Simply install
    magic-wormhole on the other computer and follow the instructions at the end
    if the debug output.

    Example::

    \b
        $ netlab debug --wormhole --install-wormhole
        2024-09-11 21:12:55 [info     ] writing file     path=/tmp/netlab_debug_0y5xltrx.txt
        ─────────────────────────────── Collecting system data ───────────────────────────────
        ───────────────────────────── Checking netlab sdk config ─────────────────────────────
        ───────────────────────────── Running `openssl s_client` ─────────────────────────────
        ──────────────────────────── Finished `openssl s_client` ─────────────────────────────
        ─────────────────────────── Debug data collection complete ───────────────────────────
        Sending 9.7 kB file named 'netlab_debug_0y5xltrx.txt'
        Wormhole code is: 88-headwaters-blowtorch
        On the other computer, please run:

        wormhole receive 88-headwaters-blowtorch

    In this example, you would run `wormhole receive 88-headwaters-blowtorch`
    on the reciving computer.
    """

    logging.config.dictConfig(LOGGING)

    wormhole_cmd = find_wormhole()

    if wormhole_cmd is None and install_wormhole:
        log.info("trying to install magic-wormhole")
        asyncio.run(run_install_wormhole())

        wormhole_cmd = find_wormhole()

    if wormhole and wormhole_cmd is None:
        log.error("wormhole command not found")
        exit(1)

    if output_file is None or wormhole:
        fd, output_file = tempfile.mkstemp(".txt", "netlab_debug_")

    if output_file or wormhole:
        log.info(f"writing file {output_file=}")

        log_config: Any = copy.deepcopy(LOGGING)

        log_config["root"]["handlers"].append("output_file")
        log_config["handlers"]["output_file"] = {
            "class": "logging.FileHandler",
            "formatter": "default",
            "filename": output_file,
            "mode": "w",
        }

        logging.config.dictConfig(log_config)

    asyncio.run(debugger.main(system=system))

    if wormhole:
        asyncio.run(run_wormhole(wormhole_cmd, output_file))
