#!/usr/bin/env python3
# Call me like this: "scl-alias --print bash | source"
# This does not seem to work in zsh. Workaround: "scl-alias -p zsh > /tmp/zsh && source /tmp/zsh"
import argparse
import os
import sys
from typing import Callable
# import the code from this package
import shell_command_logger
from shell_command_logger.alias import print_text_to_source, load_alias_file, save_alias_file, CONFIG_FILE
import shell_command_logger.cli.alias
import shell_command_logger.cli.config
import shell_command_logger.cli.log
import shell_command_logger.cli.replay

class SubcommandHandlerException(Exception):
    pass

class SubcommandHandler:
    def __init__(self, argument_parser, subcommand_variable_name: str = "subcommand", subcommand_required: bool = False) -> None:
        self.ap = argument_parser
        self.subcommand_variable_name = subcommand_variable_name
        self.ap_subparsers = self.ap.add_subparsers(metavar="SUBCOMMAND", required=subcommand_required, dest=subcommand_variable_name)
        # Maps from subcommand names to the coresponding main functions
        self.main_function_map: dict[str, Callable] = {}

    def register_module(self, module) -> None:
        for name in module.SUBCOMMAND_NAMES:
            ap_module = self.ap_subparsers.add_parser(name, **module.ARG_PARSER_OPTIONS)
            module.populate_agrument_parser(ap_module)

            if name in self.main_function_map:
                raise SubcommandHandlerException(f"The subcommand '{name}' is specified twice")

            self.main_function_map[name] = module.subcommand_main

    def subcommand_main(self, args) -> int:
        subcommand_name = getattr(args, self.subcommand_variable_name)
        if not subcommand_name:
            # If no subcommand is specified, we show the help
            self.ap.print_help()
            return 1

        fn_main = self.main_function_map.get(subcommand_name)
        if fn_main:
            fn_main(args)
        else:
            raise SubcommandHandlerException(f"No subcommand with name '{subcommand_name}' registered")


def main():
    # Register the calling binaries path
    shell_command_logger.cli.log.set_script_file(__file__)
    if symlink_name := shell_command_logger.cli.log.get_name_when_called_by_symlink():
        exit_code = shell_command_logger.cli.log.record_command_when_called_by_symlink(symlink_name, sys.argv[1:])
        sys.exit(exit_code)

    # Setting up argument parser
    ap = argparse.ArgumentParser(description="The shell-command-logger (scl) allows you to record commands. Afterwards the recorded commands can be replay and searched (not implemented yet).",
        epilog=f"Installed version: {shell_command_logger.get_version_string()}")
    ap.add_argument("-V", "--version", action="version", version=shell_command_logger.get_version_string())
    handler = SubcommandHandler(ap)
    handler.register_module(shell_command_logger.cli.alias)
    handler.register_module(shell_command_logger.cli.config)
    handler.register_module(shell_command_logger.cli.log)
    handler.register_module(shell_command_logger.cli.replay)

    # Run the selected submodule
    args = ap.parse_args()
    exit_code = handler.subcommand_main(args)
    sys.exit(exit_code)

if __name__ == "__main__":
    main()

