import os
import yaml
import json
import shutil
from pathlib import Path 

from speedbuild.utils.markdown.yaml import read_yaml 
from speedbuild.utils.cli.output import StatusManager
from speedbuild.utils.cleanup.template.clear_folder import clear_folder 
from speedbuild.frameworks.django.utils.venv_utils import get_activated_venv 
from speedbuild.frameworks.django.utils.django_utils import ManageDjangoSettings 
from speedbuild.utils.template.file import findFilePath, get_template_output_path 
from speedbuild.utils.template.template_update import checkTemplateForVersionUpdate 
from speedbuild.frameworks.django.extraction.feature_dependencies import arrangeChunks 
from speedbuild.frameworks.django.extraction.extract import extract_feature_code_and_dependencies, getTemplateFileNames, getURLForFeature 

from .test_agent import SpeedBuildTestAgent


def debugTemplate(template,packageToNameMapping,installedPackages):
    debugger = SpeedBuildTestAgent()
    full_template_path = os.path.join(debugger.home,".sb_zip",template,"lts.zip")

    if not os.path.exists(full_template_path):
        print(f"Template with name {template} does not exist")
        return
    
    ran_debug, packages_before_debug = debugger.TestFeature(template)

    if ran_debug: # if AI debugged code, update extracted feature else do nothing
        packages_after_debug = debugger.getPackagesinVenv()
        new_packages = list(packages_after_debug.difference(packages_before_debug)) #packages installed by debug
        if len(new_packages) > 0:
            # save new packages
            save_path = os.path.join(debugger.home,".sb","django_package_cache.json")
            if not(os.path.dirname(save_path)):
                os.makedirs(os.path.dirname(save_path))

            with open(save_path,"w") as file:
                json.dump({"packages":new_packages},file,indent=4)

        path_to_template = os.path.join(debugger.home,".sb","sb_extracted")
        template_root = os.path.join(path_to_template,template)
        feature_name = template.replace("speed_build_","")
        config_file_path = os.path.join(template_root,f"sb_{feature_name}.yaml")
        data = read_yaml(config_file_path)

        feature_path = os.path.join("speedbuild_app",os.path.basename(data['feature_file_path']))
        project_root = os.path.join(debugger.home,".sb","environment","django","speedbuild_project")

        # delete old zip file before repackaging
        os.remove(full_template_path)

        # re-extract debug feature
        createTemplate(
            feature_path, 
            feature_name,
            "speedbuild_project",
            packageToNameMapping,
            project_root,
            True,
            installedPackages,
            run_debug=False
        )
    else:
        logger = StatusManager()
        logger.print_message(f"Template `{template}` Created")

# remove comments from code before splitting blocks
def create_temp_from_feature(
        project_path,
        project_name,
        feature_name,
        feature_file_path,
        template_django_apps,
        installedPackages,
        skip_debug
    ):

    venv = get_activated_venv()
    
    # get settings conf from django.conf.settings TODO
    app_name = os.path.dirname(feature_file_path)

    if app_name == os.path.abspath(app_name): #incase app_name holds an abs path just get the base name
        app_name = os.path.basename(app_name)


    findFilePath(project_path, "urls.py")

    # use conditional statement to check if file is found
    project_name = findFilePath(project_path, "asgi.py")

    if len(project_name) == 0:
        raise(ValueError("Cannot find django project settings file"))
    
    template_dep = set()
    installed_apps = set()
    project_name = project_name[0].split("/")[0]
    settings_path = os.path.join(project_path, project_name,"settings.py")

    project_dir = [folder for folder in os.listdir(project_path) if os.path.isdir(os.path.join(project_path,folder))]

    settings = ManageDjangoSettings(settings_path,venv)

    processed = set()


    # start; make recursive

    output_folder_name = "sb_output_"+feature_name

    template_settings_import,template_confs,template_dep = extract_feature_code_and_dependencies(
        feature_file_path,
        feature_name,
        project_path,
        project_dir,
        app_name,
        template_django_apps,
        settings,
        project_name,
        installed_apps,
        template_dep,
        processed,
        [],
        None,
        output_folder_name,
        installedPackages
    )

    # end recursion
    output_dir = os.path.join(".","output",output_folder_name)

    # Create template yaml file
    template_confs = arrangeChunks(template_confs,[],[])

    django_package_cache_path = os.path.join(str(Path.home()),".sb","django_package_cache.json")

    if os.path.exists(django_package_cache_path):
        with open(django_package_cache_path) as package_cache:
            package_cache = json.loads(package_cache.read())
            template_dep = template_dep.union(set(package_cache['packages']))

        # remove cache packages
        os.remove(django_package_cache_path)
    
    data = {
        "feature" : feature_name,
        "feature_file_path" : feature_file_path.replace(project_path,""),
        "source_project":project_name,
        "dependencies" : list(template_dep),
        "settings" : {
            "imports" : list(sorted(set(template_settings_import))),
            "installed_apps" : list(installed_apps),
            "middlewares" : settings.getTemplateMiddleWare(list(installed_apps)),
            "configurations" : template_confs#list(set(template_confs))
        }
    }

    yaml_file_path = os.path.join(output_dir,f"sb_{feature_name}.yaml")

    with open(yaml_file_path, 'w') as file:
        yaml.dump(data, file, default_flow_style=False,sort_keys=False)


    if os.path.exists(os.path.join(output_dir,"sb_app","views.py")):
        # if views.py in models, generate url for feature
        getURLForFeature(feature_name,feature_file_path,app_name,project_path,output_folder_name)

    # create template documentations here
    tem_files = getTemplateFileNames(output_dir)
    tem_files = sorted(tem_files, key=lambda x: not x.startswith('.sb_utils')) #process dependencies first
    # Exclude the yaml file

    # for file in tem_files:
    #     file_name = file.split("/")
    #     main_file = file_name.pop().split(".")[0] #remove extention from file name
    #     file_name.append(main_file)
    #     file_name = "_".join(file_name)
  
    #     main_dir = "./output/documentation"
    #     if not os.path.exists(main_dir):
    #         os.makedirs(main_dir)

    #     # write to file  TODO : leave commented for now
    #     with open(f"{main_dir}/{file_name}.md","w") as new_file:
    #         # get and write doc to file
    #         pass
    #         # doc = documentationAgent(file)
    #         # new_file.write(doc)

    # Save template to user main dir in the .sb_zip folder
    user_dir = str(Path.home())
    user_dir = os.path.join(user_dir,".sb_zip")

    if not os.path.exists(user_dir):
        os.makedirs(user_dir)

    template_path = get_template_output_path(feature_name)

    shutil.make_archive(template_path, 'zip', output_dir)


    # delete output folder
    clear_folder(output_dir)
    
    # structure templates to include versions
    if skip_debug:
        checkTemplateForVersionUpdate(template_path)
    else:
        shutil.move(f"{template_path}.zip", os.path.join(template_path, "lts.zip"))

    return template_path


def createTemplate(
        file_path, 
        feature,
        project_name,
        packageToNameMapping,
        project_root,
        append_root=False,
        installedPackages={},
        run_debug=True
    ):

    logger = StatusManager()

    if file_path.endswith("/"):
        file_path = file_path.lstrip("/")

    if append_root:
        file_path = os.path.join(project_root,file_path)
    else:
        file_path = file_path.replace(project_root,"")

    if run_debug:
        logger.start_status("Extracting Feature")
    else:
        logger.start_status("Re-extracting debugged feature")

    # print("\n##### Extracting Feature : ",feature," ##### from ",file_path)

    if not os.path.exists(file_path):
        print("invalid feature")
        return

    template_path = create_temp_from_feature(
        project_root,
        project_name,
        feature,
        file_path,
        packageToNameMapping,
        installedPackages,
        run_debug
    )

    logger.stop_status("Feature Extracted")


    # debug template to catch error our algorithm missed
    if run_debug:
        os.environ['run_documentation'] = "True"
        debugTemplate(os.path.basename(template_path),packageToNameMapping,installedPackages)

    if not run_debug:
        os.environ['run_documentation'] = "False"
        # TODO : run index for RAG
        logger.print_message(f"Template `{template_path}` Created")
