"""Entrance point for Mariner application."""

import logging
import logging.handlers
import pathlib
import sys

import colorama
import uvloop
from cliff import app, commandmanager

from mariner import __version__, config
from mariner.clients.http import AsyncClient, ClientConfig
from mariner.services.downloader import Service as DownloadService
from mariner.services.registry import TrackerRegistry
from mariner.services.search import Service as SearchService
from mariner.utils import path


class Mariner(app.App):
    """Interactive CLI for Mariner."""

    log = logging.getLogger(__name__)

    def __init__(self):
        super().__init__(
            description=__version__.__description__,
            version=__version__.__version__,
            command_manager=commandmanager.CommandManager("mariner.cli"),
            deferred_help=True,
        )
        self.config = None
        self.engine = None
        self.http_client = None

    def build_option_parser(self, description, version, argparse_kwargs=None):
        """Return an Argparse option parser for Mariner.

        Args:
            description: Mariner description.
            version: Mariner version.

        """
        # Override the help message for log output
        kwargs = {"conflict_handler": "resolve"}
        parser = super().build_option_parser(description, version, kwargs)
        parser.add_argument(
            "--log-file",
            action="store",
            default=None,
            help="Path to log output. Default ~/.local/share/mariner/mariner.log.",
        )
        parser.add_argument(
            "--config-file",
            "-c",
            action="store",
            default=None,
            help="Path to config file. Default ~/.config/mariner/config.yaml",
        )
        return parser

    def configure_logging(self):
        """Create logging handlers for any log output."""
        root_logger = logging.getLogger("")
        root_logger.setLevel(logging.DEBUG)

        # Suppress noisy HTTP request logging from httpx
        logging.getLogger("httpx").setLevel(logging.WARNING)
        logging.getLogger("httpcore").setLevel(logging.WARNING)

        # Set logging to file by default.
        if not self.options.log_file:
            log_dir = path.log()
            log_dir = path.exists_or_create(log_dir)
            self.options.log_file = str(pathlib.Path(log_dir) / "mariner.log")

        # Monkey patched to use RotatingFileHandler
        file_handler = logging.handlers.RotatingFileHandler(
            filename=self.options.log_file,
            maxBytes=1000000,
            backupCount=1,
        )
        formatter = logging.Formatter(self.LOG_FILE_MESSAGE_FORMAT)
        file_handler.setFormatter(formatter)
        root_logger.addHandler(file_handler)

        # Always send higher-level messages to the console via stderr
        console = logging.StreamHandler(self.stderr)
        console_level = {
            0: logging.WARNING,
            1: logging.INFO,
            2: logging.DEBUG,
        }.get(self.options.verbose_level, logging.DEBUG)
        console.setLevel(console_level)
        formatter = logging.Formatter(self.CONSOLE_MESSAGE_FORMAT)
        console.setFormatter(formatter)
        root_logger.addHandler(console)

    def initialize_app(self, argv: list[str]) -> None:
        """Initialize the application.

        Args:
          argv: List[str]: List of command line arguments.

        """
        self.LOG.debug("Initialize Mariner")

        if self.options.config_file:
            self.config = config.Config(configpath=self.options.config_file)
        else:
            self.config = config.Config()

        # Older configurations have no timeout option
        try:
            raw_timeout = self.config["timeout"]
            timeout = int(raw_timeout) if isinstance(raw_timeout, (str, int)) else 10
        except KeyError:
            timeout = 10
            self.config["timeout"] = timeout

        self._loop = uvloop.new_event_loop()
        self.http_client = AsyncClient(ClientConfig(timeout=timeout))
        user_defs_dir = path.user_definitions()
        definition_downloader = DownloadService(
            client=self.http_client,
            download_path=user_defs_dir,
        )
        registry = TrackerRegistry(
            client=self.http_client,
            definition_downloader=definition_downloader,
            user_definitions_dir=user_defs_dir,
        )
        self.engine = SearchService(registry=registry, loop=self._loop)

        if self.interactive_mode:
            self.log.info("Welcome to Mariner. Navigate torrents with CLI!")
            self.log.info(
                'Type "help" to get started.',
            )
            self.log.info(
                "Documentation is at https://radek-sprta.gitlab.io/mariner.",
            )

    def prepare_to_run_command(self, cmd) -> None:
        """Code to run before command.

        Args:
          cmd: Command to run.

        """
        self.LOG.debug("Preparing to run command %s", cmd.__class__.__name__)

    def clean_up(self, cmd, result, err) -> None:
        """Code to run after command.

        Args:
          cmd: Command that was run.
          result: Result of the command.
          err: Errors caught while running the command.

        """
        self.LOG.debug("Clean up %s", cmd.__class__.__name__)
        if err:
            self.LOG.debug("Got an error: %s", err)


def main(argv=sys.argv[1:]):  # pylint: disable=dangerous-default-value
    """Application entrance point.

    Args:
      argv: Defaults to sys.argv[1:]. Command line argument list.

    """
    # Initialize color output
    colorama.init()

    mariner = Mariner()
    return mariner.run(argv)


if __name__ == "__main__":
    sys.exit(main(sys.argv[1:]))
