import argparse
import os
import signal
import subprocess
import sys

from loguru import logger

from .iechelle import IechelleLib
from iechelle import __author__
from iechelle import __copyright__
from iechelle import __description__
from iechelle import __version__


class SmartFormatter(argparse.HelpFormatter):
    """Smart formatter for argparse - The lines are split for long text"""

    def _split_lines(self, text, width):
        if text.startswith("R|"):
            return text[2:].splitlines()
        # this is the RawTextHelpFormatter._split_lines
        return argparse.HelpFormatter._split_lines(  # pylint: disable=protected-access
            self, text, width
        )


class SigintHandler:  # pylint: disable=too-few-public-methods
    """Handles the signal"""

    def __init__(self):
        self.SIGINT = False  # pylint: disable=invalid-name

    def signal_handler(self, sig: int, frame):
        """Trap the signal

        Args:
            sig (int): the signal number
            frame: the current stack frame
        """
        # pylint: disable=unused-argument
        logger.error("You pressed Ctrl+C")
        self.SIGINT = True
        sys.exit(2)


def str2bool(string_to_test: str) -> bool:
    """Checks if a given string is a boolean

    Args:
        string_to_test (str): string to test

    Returns:
        bool: True when the string is a boolean otherwise False
    """
    return string_to_test.lower() in ("yes", "true", "True", "t", "1")


def parse_cli() -> argparse.Namespace:
    """Parse command line inputs.

    Returns
    -------
    argparse.Namespace
        Command line options
    """
    parser = argparse.ArgumentParser(
        description=__description__,
        formatter_class=SmartFormatter,
        epilog=__author__ + " - " + __copyright__,
    )
    parser.add_argument(
        "-v", "--version", action="version", version="%(prog)s " + __version__
    )

    parser.add_argument(
        "--conf_file",
        default="conf/iechelle.conf",
        help="The location of the configuration file (default: %(default)s)",
    )

    parser.add_argument(
        "--directory",
        default="/app",
        help="The base directory where the data products are read and saved (default: %(default)s)",
    )

    parser.add_argument(
        "--level",
        choices=[
            "INFO",
            "DEBUG",
            "WARNING",
            "ERROR",
            "CRITICAL",
            "TRACE",
        ],
        default="INFO",
        help="set Level log (default: %(default)s)",
    )

    return parser.parse_args()


def run():
    """Main function that launches the Bokeh GUI."""
    try:
        # Get the path to the gui directory within the package
        gui_path = os.path.join(os.path.dirname(__file__), "gui")

        # Clean up port 5006 if it's already in use (common in development)
        try:
            subprocess.run(
                "lsof -ti:5006 | xargs kill -9",
                shell=True,
                stderr=subprocess.DEVNULL,
                stdout=subprocess.DEVNULL,
            )
        except Exception:
            pass

        # Build the command to run bokeh serve
        # Replicates the 'make run' command logic
        cmd = [
            sys.executable,
            "-m",
            "bokeh",
            "serve",
            gui_path,
            "--show",
            "--session-token-expiration",
            "3600",
            "--check-unused-sessions",
            "1000",
            "--unused-session-lifetime",
            "1000",
        ]

        # Optionally, we could pass CLI arguments to bokeh but let's keep it standard for now.
        # Use subprocess.run to execute the bokeh server.
        # KeyboardInterrupt will be handled naturally.
        subprocess.run(cmd)

    except KeyboardInterrupt:
        sys.exit(0)
    except Exception as error:  # pylint: disable=broad-except
        logger.exception(error)
        sys.exit(1)


if __name__ == "__main__":
    # execute only if run as a script
    run()
