import os
import json
from shutil import rmtree

from requests import exceptions
import getpass

from .utils import log
from .utils import files
from .ractf import CTF

DO_NOT_TOUCH_COMMENT = "This file is automatically generated and used by RACLI to track state. Don't modify it unless you know what you're doing."

def init_ctf():
    ctf_info = files.find_file(".ctf.json")
    if not ctf_info:
        log.error_and_quit("Could not find .ctf.json, have you cloned?")

    with open(ctf_info, "r") as f:
        ctf_info = json.load(f)

    ctf = CTF(ctf_info["api_url"])
    ctf.auth_token = f"{ctf_info['token']}"

    return ctf

def clone(api_url):
    ctf = CTF(api_url)

    ctf.get_config()

    try:
        clone_into = ctf.get_config()["flag_prefix"]
    except (exceptions.ConnectionError, ractf.errors.APIError, KeyError):
        log.error_and_quit("Failed to get CTF information from that URL. Please ensure you have supplied a valid API base.")

    if os.path.exists(clone_into):
        log.error_and_quit(f"Path '{clone_into}' already exists. Aborting.")

    log.info(f"Cloning CTF into '{clone_into}'...")

    username = input("Username: ")
    password = getpass.getpass("Password: ")
    otp = getpass.getpass("OTP (Leave blank if none): ")

    try:
        ctf.login(username=username,password=password,otp=otp)
    except ractf.errors.APIError:
        log.error_and_quit("Could not login with supplied credentials")
    
    ctf_store = {
        "_comment": DO_NOT_TOUCH_COMMENT,
        "token": ctf.auth_token,
        "api_url": ctf.api_base,
    }
    
    os.mkdir(clone_into)
    
    for category in ctf.get_categories():
        os.mkdir(f"{clone_into}/{category.name}")

        with open(f"{clone_into}/{category.name}/.category.json", "w+") as f:
            json.dump({"_comment": DO_NOT_TOUCH_COMMENT, "id": category.id}, f)

        for challenge in category.challenges:
            if challenge.unlocked:
                os.mkdir(f"{clone_into}/{category.name}/{challenge.name}")

                with open(f"{clone_into}/{category.name}/{challenge.name}/brief.md", "w+", encoding="utf-8") as f:
                    f.write(f"# {challenge.name}\n\n{challenge.description}")

                with open(f"{clone_into}/{category.name}/{challenge.name}/.challenge.json", "w+") as f:
                    json.dump({"_comment": DO_NOT_TOUCH_COMMENT, "id": challenge.id}, f)
            else:
                os.mkdir(f"{clone_into}/{category.name}/Locked challenge [ID {challenge.id}]")

    with open(f"{clone_into}/.ctf.json", "w+") as f:
        json.dump(ctf_store, f)
    
    log.success("CTF Cloned!")
    
def submit(flag):
    ctf = init_ctf()

    challenge_info = files.find_file(".challenge.json")
    if not challenge_info:
        log.error_and_quit("Could not find .challenge.json, are you in a challenge directory?")
    with open(challenge_info, "r") as f:
        challenge_info = json.load(f)

    challenge = ctf.get_challenge(challenge_info["id"])
    if challenge.submit_flag(flag):
        log.success("Correct flag submitted. Well done!")
        if len(challenge.unlocks) > 0:
            log.warn("You may have unlocked additional challenges, make sure to check.")
            for challenge in challenge.unlocks:
                challenge = ctf.get_challenge(challenge)
                cat_root = files.get_cat_root()
                rmtree(f"{cat_root}/Locked challenge [ID {challenge.id}]")

                os.mkdir(f"{cat_root}/{challenge.name}")

                with open(f"{cat_root}/{challenge.name}/brief.md", "w+", encoding="utf-8") as f:
                    f.write(f"# {challenge.name}\n\n{challenge.description}")

                with open(f"{cat_root}/{challenge.name}/.challenge.json", "w+") as f:
                    json.dump({"_comment": DO_NOT_TOUCH_COMMENT, "id": challenge.id}, f)
    else:
        log.info("Flag rejected. Keep trying!")
