import os, shutil
from coursebox.core.info_paths import get_paths
from coursebox.core.info import class_information
from snipper.snip_dir import snip_dir
from coursebox.material.homepage_lectures_exercises import fix_shared
from snipper.snipper_main import censor_file
from pathlib import Path
import fnmatch

def setup_student_files(run_files=True,
                        cut_files=True,
                        censor_files=True,
                        week=None, extra_dirs=None,
                        include_solutions=None,
                        projects=None,
                        setup_lectures=False, strict=True,
                        fix_shared_files=True,
                        include_exam_examples=False, # Include the directory with exam-related examples.
                        verbose=True,
                        students_irlc_tools=None, # Destination dir for the irlc folder (the one we really want to deploy).
                        midterms=None, # Can be a list: [0, 1]
                        include_docs=False, # Include the documentation directory, i.e. 02465public/pythontools/docs.
                        convert_svg=True, # Whether to convert SVG file when deploying. Leave to true, unless we are doing CI/CD in which case inkscape may not be installed.
                        package="cp",
                        fix_shared_files_func=None,
                        ):

    if midterms is None:
        midterms = []
    from coursebox.core import info_paths

    week = [week] if isinstance(week, int) else week
    if verbose:
        print("toolbox running. Fixing student files by copying to student dir")
    paths = get_paths()
    if include_solutions is None:
        include_solutions = []

    if projects is None:
        projects = []

    public_irlc_tools = paths['02450public'] + "/src/cp"

    if students_irlc_tools is None:
        if censor_files:
            students_irlc_tools = paths['02450students'] + "/cp"
        else:
            students_irlc_tools = paths['02450students'] + "_complete/cp"

    if not os.path.isdir(students_irlc_tools):
        os.makedirs(students_irlc_tools)

    init_dest = students_irlc_tools+"/__init__.py"
    shutil.copy(public_irlc_tools + "/__init__.py", init_dest)
    if os.path.isfile(public_irlc_tools + "/../.coveragerc"):
        shutil.copy(public_irlc_tools + "/../.coveragerc", students_irlc_tools+ "/../.coveragerc")
    # assert False
    censor_file(init_dest)

    # Check for exclusion mask.
    exclude = info_paths.core_conf.get('student_files', {}).get('exclude', [])

    exclude += [f'tests_week{w if w >= 10 else f"0{w}"}.py' for w in range(0,14) if w not in week]
    exclude = exclude + ["**/" + ex for ex in exclude]
    if not include_exam_examples:
        exclude += ['exam_tabular_examples']
    inclusion = [] # 'ex09old/cache']
    hws = []
    for m in midterms:
        # Copy the midterm from the exam directory into the public repository. This will ensure the midterm is later propagated to the student directory.
        # The midterm should always be distributed as a .zip file: This is the only legal distribution mechanism.
        # The midterm in the student directory does not need to be super-duper up to date. This is not the file which is distributed 'officially'.
        if verbose:
            print(m)

    if extra_dirs is None:
        extra_dirs = ['utils', 'tests', 'exam/exam2023spring'] # 'assignments',
        for m in midterms:
            if m == 0:
                extra_dirs += ['exam/midterm2023a']
            if m == 1:
                extra_dirs += ['exam/midterm2023b']

        # if include_exam_examples:
        #     extra_dirs += ['exam_tabular_examples']
        if setup_lectures:
            extra_dirs += [
                # 'lectures/chapter0pythonC',
                # 'lectures/chapter0pythonA',
                # 'lectures/chapter0pythonB',
                # 'lectures/chapter1',
                'lectures',
                # 'workshop'
            ]

        import coursebox.core.info

        for id in projects:
            # if setup_projects:
            if 'projects_all' in info_paths.core_conf:
                p = info_paths.core_conf['projects_all'][id]['class']
                extra_dirs += [os.path.basename(os.path.dirname(p.mfile()))]
            else:

                if id <= 3:
                    extra_dirs += [f'project{id}'] # , 'project1', 'project2', 'project3']
                else:
                    extra_dirs.append(f'project3i')

    if week is not None:
        for w in week:
            ex = str(w)
            ex = "ex" + ("0" + ex if len(ex) < 2 else ex)
            base = public_irlc_tools +"/"+ex
            if not os.path.isdir(base):
                continue
            d = {'base': base,
                 'out': students_irlc_tools +"/"+ex,
                 'exclusion': exclude,
                 'inclusion': inclusion,
                 'include_solutions': w in include_solutions,
                 'week': w}
            hws.append(d)

        weekn = 101
        for weekn, d in enumerate(extra_dirs):
            dutil = {'base': public_irlc_tools + "/" + d,
                 'out': students_irlc_tools + "/" + d,
                 'exclusion': exclude,
                 'inclusion': inclusion,
                'include_solutions': False,
                 'week': f'{weekn+100}'}
            hws.append(dutil)
        weekn += 1

    else:
        raise Exception("Specify a week")

    if len(hws) >  0:
        info = class_information(verbose=verbose)
        # print("references") # Bad idea because of the very long output.
        # print(info['references']['commands'])
    else:
        info = None
    for hw in hws:
        n = fix_hw(paths=paths, info=info, hw=hw, out= hw['out'], output_dir=paths['shared'] +"/output", run_files=run_files, cut_files=cut_files,
                   package_base_dir=os.path.dirname(students_irlc_tools), censor_files=censor_files, strict=strict,
                   include_solutions=hw.get('include_solutions', False),
                   verbose=verbose)

        with open(paths['shared'] + f"/output/lines_{hw['week']}.txt", 'w') as f:
            f.write(str(n))


    if fix_shared_files:
        if verbose:
            print("> Homework fixed, copying shared files...")
        fix_shared_files_func(paths=paths, compile_templates=False, verbose=verbose, dosvg=convert_svg)

    if verbose:
        print("> Removing excluded files from students gitlab directory...")
    # for f in exclude + ["lectures"]:
    for l in list(Path(students_irlc_tools).glob('**/*')):
        if not os.path.exists(l):  # May have been removed as part of a subtree
            continue
        m = [ ex for ex in exclude if fnmatch.fnmatch(l, ex)]
        if len(m) > 0:
            if os.path.isdir(l):
                shutil.rmtree(l)
            else:
                os.remove(l)

    shutil.copy(public_irlc_tools +"/../requirements.txt", students_irlc_tools +"/../requirements.txt")
    # shutil.copy(public_irlc_tools +"/../requirements_conda.txt", students_irlc_tools +"/../requirements_conda.txt")
    # Don't think we need this anymore. Why copy docs if they cannot be compiled anyway? Perhaps for the complete docs?
    if include_docs:
        if os.path.isdir(students_irlc_tools + "/../docs"):
            shutil.rmtree(students_irlc_tools + "/../docs")
        # if not censor_files:
        shutil.copytree(public_irlc_tools + "/../docs", students_irlc_tools + "/../docs")
        # Fix reference to output.
        snip_dir(public_irlc_tools + "/../docs/source", students_irlc_tools + "/../docs/source", run_files=False, cut_files=False, censor_files=False, references=info['references'], verbose=verbose)
    if verbose:
        print("> All student file stuff completed.")



def fix_hw(paths, info, hw, out, output_dir, run_files=False, cut_files=False, censor_files=True,
           include_solutions=False,
           package_base_dir=None,  # When runing files using #!o, this specify the base directory of the  package the files resides in. Can be None.
           verbose=True,
           **kwargs):

    n, cutouts = snip_dir(source_dir=hw['base'], dest_dir=out, output_dir=output_dir, exclude=hw['exclusion'], references=info['references'],
                 run_files=run_files, cut_files=cut_files, license_head=info.get('code_copyright', None),
                 censor_files=censor_files,verbose=verbose,package_base_dir=package_base_dir)

    if include_solutions:
        wk = hw['base'].split("/")[-1]
        sp = paths['02450students'] + "/solutions/"
        if not os.path.exists(sp):
            os.mkdir(sp)
        sp = sp + wk
        if os.path.isdir(sp):
            shutil.rmtree(sp)
        # if not os.path.exists(sp):
        os.mkdir(sp)

        for f, cut in cutouts.items():
            if len(cut) > 0:
                fname = os.path.basename(f)
                sols = []
                stext = ["\n".join(lines) for lines in cut]
                for i, sol in enumerate(stext):
                    sols.append((sol,))
                    sout = sp + f"/{os.path.basename(fname)[:-3]}_TODO_{i + 1}.py"
                    wsol = True
                    print(sout, "(published)" if wsol else "")
                    if wsol:
                        with open(sout, "w") as f:
                            f.write(sol)

    return n
