import importlib.util
import subprocess as sp
import os
import sys
from pathlib import Path
import sys
import argparse
from loguru import logger

from gitchat import __version__
from gitchat.core import add_user, Chat, git


def get_handler(file_path):
    """Obtains `handler` func from file_path"""
    if not os.path.isfile(file_path):
        raise FileNotFoundError(f"File not found: {file_path}")

    module_name = os.path.splitext(os.path.basename(file_path))[0]

    spec = importlib.util.spec_from_file_location(module_name, file_path)
    if spec is None:
        raise ImportError(f"Could not create a spec for {file_path}")

    module = importlib.util.module_from_spec(spec)

    try:
        spec.loader.exec_module(module)
    except Exception as e:
        raise ImportError(f"Error executing module {file_path}: {e}") from e

    if hasattr(module, "handler") and callable(module.handler):
        return module.handler
    raise ValueError("Function `handler` was not found!")


def main():
    parser = argparse.ArgumentParser(description="GitChat cli app")
    subparsers = parser.add_subparsers(dest="command", help="Available commands")

    conf_parser = subparsers.add_parser(
        "config", aliases=["cfg"], help="Configure git repo for chatting"
    )
    conf_parser.add_argument(
        "--username", "-u", dest="username", help="Username for chat"
    )
    conf_parser.add_argument(
        "--repo", "-r", dest="repo", help="Path to clonned git repo"
    )

    chat_parser = subparsers.add_parser("chat", aliases=["ch"], help="Start chatting")
    chat_parser.add_argument(
        "--username", "-u", dest="username", help="Username for chat"
    )
    chat_parser.add_argument(
        "--repo", "-r", dest="repo", help="Path to clonned git repo"
    )
    chat_parser.add_argument(
        "--handler", dest="handler", help="Path to file with handler func"
    )
    chat_parser.add_argument(
        "--password", "-p", dest="password", help="Password for encoding/decoding"
    )
    chat_parser.add_argument(
        "--delay",
        "-d",
        dest="delay",
        default=1.0,
        type=float,
        help="Delay between new messages checks",
    )

    login_parser = subparsers.add_parser(
        "login", help="Add git server credentials"
    )
    login_parser.add_argument(
        "--username", "-u", dest="username", help="Username for git server"
    )
    login_parser.add_argument(
        "--password", "-p", dest="password", help="Password for git server"
    )
    login_parser.add_argument(
        "--repo", "-r", dest="repo", help="Repo URL"
    )
    login_parser.add_argument(
        "--creds-file", "-c", dest="creds_file", help="File with git credentials (~/.git-credentials often)"
    )

    subparsers.add_parser("version", aliases=["v"], help="Get project version")

    args = parser.parse_args()

    if args.command in ["config", "cfg"]:
        if not args.username:
            logger.error("Please, provide username via -u flag!")
            exit(-1)
        if not args.repo:
            logger.error("Please, specify repo path!")
            exit(-1)
        handle_config(args)
    elif args.command in ["chat", "ch"]:
        if not args.username:
            logger.error("Please, provide username via -u flag!")
            exit(-1)
        if not args.repo:
            logger.error("Please, specify repo path!")
            exit(-1)
        handle_chat(args)
    elif args.command == "login":
        if not args.username:
            logger.error("Please, provide username for git server via -u flag!")
            exit(-1)
        if not args.password:
            logger.error("Please, provide password for git server via -p flag!")
            exit(-1)
        if not args.repo:
            logger.error("Please, provide repo URL via -r flag!")
            exit(-1)
        if not args.creds_file:
            logger.error("Please, provide path to creds for git via -c flag! (~/.git-credentials often)")
            exit(-1)
        handle_login(args)
    elif args.command in ["version", "v"]:
        print(f"Current version is `{__version__}`")
    else:
        parser.print_help()
        sys.exit(1)


def handle_config(args):
    logger.debug(f"Initialization for username `{args.username}` ...")
    if not (Path(args.repo) / ".git").exists():
        logger.error(
            f"Can not find git repo in `{args.repo}` - ensure that you clonned it!"
        )
        exit(-1)
    # Adding user to repo
    try:
        add_user(username=args.username, cwd=args.repo)
    except Exception as e:
        logger.error(f"Failed to register new user in repo: {e}")
        exit(-1)
    logger.success(f"User `{args.username}` successfully added to repo")


def handle_chat(args):
    logger.debug(f"Starting chat for `{args.username}` ...")
    handler_func = None
    if args.handler:
        try:
            handler_func = get_handler(args.handler)
        except Exception as e:
            logger.error(f"Failed to get handler from file `{args.handler}`: {e}")
            exit(-1)
    chat = Chat(
        username=args.username,
        delay=args.delay,
        handler=handler_func,
        password=args.password,
        cwd=args.repo,
    )
    chat.start()

def handle_login(args):
    logger.debug("Configuring git to store creds in file ...")
    try:
        git("config", "--global", "credential.helper", "store", check=True)
    except sp.CalledProcessError as e:
        logger.error(f"Can not configure git: exited with code {e.returncode}")
        exit(-1)

    logger.debug("Adding user's credentials ...")

    # Extracting git server url
    if '://' in args.repo:
        host = args.repo.split('://')[1].split('/')[0]
    else:
        host = args.repo.split('/')[0]

    creds= f"https://{args.username}:{args.password}@{host}\n"

    with open(args.creds_file, "r") as f:
        if creds in f.read():
            logger.warning(f"Found dublicate of creds for `{args.username}`, skipping ...")
            return
    with open(args.creds_file, "w") as f:
        f.write(creds)
        logger.success(f"Credentials for `{args.username}` added")
    

if __name__ == "__main__":
    main()
