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, errors

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 run_clone(api_url):
    ctf = CTF(api_url)

    try:
        clone_into = ctf.get_config()["flag_prefix"]
    except:
        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 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}/{category.name}/Locked challenge [ID {challenge.id}]/locked-info.txt", "w+", encoding="utf-8") as f:
                    f.write(f"This challenge is locked. To unlock it, you first need to solve another challenge.")

    with open(f"{clone_into}/.ctf.json", "w+") as f:
        json.dump(ctf_store, f)
    
    log.success("CTF Cloned!")
    
def run_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()
                try:
                    rmtree(f"{cat_root}/Locked challenge [ID {challenge.id}]")
                except:
                    cat_root = "/" + 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!")

def run_instance():
    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"])

    try:
        instance = challenge.get_challenge_server_instance()
    except errors.APIError:
        log.error_and_quit("Failed to get challenge server instance, does this challenge have one attached?")
