import sys
import os
import glob
import json
import urllib.request
import re
import subprocess
import tempfile
import shutil

def compile_to_pdf(text, output_pdf_path): # 21 cm + 3.8 (dimension de la marge de gauche)
    """Wraps text in a standalone template and compiles it to PDF."""
    latex_template = f"""\\documentclass[varwidth=24.8cm,margin=0.4cm]{{standalone}}
\\usepackage[utf8]{{inputenc}}
\\usepackage[T1]{{fontenc}}
\\usepackage{{lmodern}}
\\usepackage{{amsmath, amssymb}}
\\usepackage{{commands}}
\\usepackage{{graphicx}}
\\usepackage{{enumitem}}
\\begin{{document}}
    \\begin{{minipage}}{{24.8cm}}
{text}
    \\end{{minipage}}
\\end{{document}}
"""
    with tempfile.TemporaryDirectory() as temp_dir:
        tex_filename = 'text.tex'
        pdf_filename = 'text.pdf'
        tex_path = os.path.join(temp_dir, tex_filename)

        with open(tex_path, 'w', encoding='utf-8') as f:
            f.write(latex_template)

        # Set TEXINPUTS so pdflatex can find commands.sty if it's in the current dir
        # env = os.environ.copy()
        # current_dir = os.getcwd()
        # env['TEXINPUTS'] = f".:{current_dir}:"

        try:
            subprocess.run(
                ['pdflatex', '-interaction=nonstopmode', tex_filename],
                cwd=temp_dir,
                stdout=subprocess.DEVNULL,
                stderr=subprocess.DEVNULL,
                check=False
            )

            generated_pdf = os.path.join(temp_dir, pdf_filename)
            if os.path.exists(generated_pdf):
                shutil.move(generated_pdf, output_pdf_path)
        except Exception as e:
            print(f"Compilation error for {output_pdf_path}: {e}")

def fetch_and_save_sub_text(ex_id, indices, label, text_path):
    """Fetches text for a specific sub-question and saves it to Text/{label}.tex"""
    qinds = ",".join(map(str, indices))
    url = f"http://localhost:8080/exercices/exo_q_text/{ex_id}/{qinds}"
    try:
        with urllib.request.urlopen(url) as response:
            content = response.read().decode('utf-8')
            content = replace_dots(content.strip("\n"))
            with open(os.path.join(text_path, f"{label}.tex"), 'w', encoding='utf-8') as f:
                f.write(content)
            # Compile PDF
            pdf_file = os.path.join(text_path, f"{label}.pdf")
            compile_to_pdf(content, pdf_file)
    except Exception as e:
        print(f"Error fetching sub-text from {url}: {e}")

def fetch_and_save_sub_sol(ex_id, indices, label, sol_path):
    """Fetches text for a specific sub-question and saves it to Text/{label}.tex"""
    qinds = ",".join(map(str, indices))
    url = f"http://localhost:8080/exercices/exo_q_sol/{ex_id}/{qinds}"
    try:
        with urllib.request.urlopen(url) as response:
            content = response.read().decode('utf-8')
            content = replace_dots(content.strip("\n"))
            with open(os.path.join(sol_path, f"{label}.tex"), 'w', encoding='utf-8') as f:
                f.write(content)
            # Compile PDF
            pdf_file = os.path.join(sol_path, f"{label}.pdf")
            compile_to_pdf(content, pdf_file)
    except Exception as e:
        print(f"Error fetching sub-text from {url}: {e}")


ROMANS_CAP = ["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX", "X"]
ROMANS_LOW = ["", "i", "ii", "iii", "iv", "v", "vi", "vii", "viii", "ix", "x"]

def replace_dots(text):
    # (?m) enables multiline mode so ^ matches start of each line
    return re.sub(r"(?m)^(\s*.)\.", r"\1)", text)

def replace_problem_labels(text):
    """Replaces labels according to spaces depth when problem=True."""
    def repl(m):
        spaces = m.group(1)
        label = m.group(2)
        n = len(spaces)
        try:
            if n == 1 and label.isdigit():     # 1 space: 1) -> I)
                return f"{spaces}{ROMANS_CAP[int(label)]})"
            elif n == 4 and label.isalpha():   # 4 spaces: a) -> 1)
                return f"{spaces}{ord(label.lower()) - 96})"
            elif n == 7 and label.isdigit():   # 7 spaces: 1) -> a)
                return f"{spaces}{chr(96 + int(label))})"
            elif n == 10 and label.isdigit():  # 10 spaces: 1) -> i)
                return f"{spaces}{ROMANS_LOW[int(label)]})"
        except (IndexError, ValueError):
            pass
        return m.group(0)

    # Matches start of line, spaces, alphanumeric label, and closing parenthesis
    return re.sub(r"(?m)^([ \t]+)([a-zA-Z0-9]+)\)", repl, text)

def format_indices(indices, problem=False):
    if not indices: return ""
    if not problem:
        res = f"{indices[0]})"
        if len(indices) > 1: res += f"{chr(96 + indices[1])})"
        if len(indices) > 2: res += f"{ROMANS_LOW[indices[2]]})"
        return res
    else:
        res = ""
        if len(indices) > 0: res += f"{ROMANS_CAP[indices[0]]})"
        if len(indices) > 1: res += f"{indices[1]})"
        if len(indices) > 2: res += f"{chr(96 + indices[2])})"
        if len(indices) > 3: res += f"{ROMANS_LOW[indices[3]]})"
        return res


def save_split_content(text, path, base_fname, problem):
    # Always save the main aggregated file
    with open(os.path.join(path, base_fname), 'w', encoding='utf-8') as f:
        f.write(text)


    pattern = re.compile(r"(?m)^([ \t]+)([a-zA-Z0-9]+)\)")
    all_matches = list(pattern.finditer(text))

    target_spaces = 4 if problem else 1
    splits = [m for m in all_matches if len(m.group(1)) == target_spaces]

    for i, match in enumerate(splits):
        start_idx = match.start()
        end_idx = splits[i+1].start() if i + 1 < len(splits) else len(text)
        chunk = text[start_idx:end_idx].strip("\n")

        label = match.group(2) + ")"

        if problem:
            # Find the most recent 1-space match before this 4-space match
            sec_match = next((m for m in reversed(all_matches)
                              if len(m.group(1)) == 1 and m.start() < match.start()), None)
            if sec_match:
                label = f"{sec_match.group(2)}){label}"

        sub_fname = f"{base_fname} : {label}"

        with open(os.path.join(path, sub_fname), 'w', encoding='utf-8') as f:
            f.write(chunk)


def process_directory(directory):
    # Find the first .tex file in the directory
    tex_files = glob.glob(os.path.join(directory, "*.tex"))
    if not tex_files:
        print(f"No .tex file found in {directory}. Looking in /Staging/Interro/")
        int_name = directory[:-1] if directory.endswith("/") else directory
        tex_path = os.path.join(os.path.expanduser("~"), "Prépa/Staging/Interro/", int_name, ".tex")
        if os.path.exists(tex_path):
            tex_file = tex_path
        else:
            print("Not found.")
            return
    else:
        tex_file = tex_files[0]

    # Prepare output directories
    paths = {
        'Text': os.path.join(directory, "Text"),
        'Sol': os.path.join(directory, "Sol"),
        'Persp': os.path.join(directory, "Persp")
    }
    for p in paths.values():
        os.makedirs(p, exist_ok=True)

    labels_file = os.path.join(directory, "labels")
    current_ex_num = 1

    # Read entirely to allow chunking
    with open(tex_file, 'r', encoding='utf-8') as f_in:
        content = f_in.read()

    # Split by the specific SHEETINFO tag
    blocks = content.split("%%SHEETINFO :")

    with open(labels_file, 'w', encoding='utf-8') as f_labels:
        # Skip blocks[0] (content before first SHEETINFO)
        for block in blocks[1:]:
            parts_line = block.split("\n", 1)
            json_str = parts_line[0].strip()
            block_content = parts_line[1] if len(parts_line) > 1 else ""

            # Check if text until next SHEETINFO block contains \Roman
            problem = r"\Roman" in block_content

            if not json_str: continue

            try:
                data = json.loads(json_str)
                # Construct 'ids' parameter
                ex_id = str(data['id'])
                selection = data.get('select')

                if selection is not None:
                    sel_s = [i+1 for i in selection]
                    ids = f"{ex_id}.{','.join(map(str, sel_s))}"
                else:
                    ids = ex_id


                # 2. Handle Labels
                indexes = data.get('indexes', [])
                if not indexes:
                    label = f"Ex {current_ex_num}"
                    f_labels.write(f"{label}\n")
                    fetch_and_save_sub_text(ids, [], label, paths['Text'])
                    fetch_and_save_sub_sol(ids, [], label, paths['Sol'])
                else:
                    for item in indexes:
                        suffix = format_indices(item['indices'], problem)
                        label = f"Ex {current_ex_num}" + (f" : {suffix}" if suffix else "")
                        f_labels.write(f"{label}\n")
                        fetch_and_save_sub_text(ids, item['indices'], label, paths['Text'])
                        fetch_and_save_sub_sol(ids, item['indices'], label, paths['Sol'])


                # Construct URL (append pb=true if \Roman matched)
                url = f"http://localhost:8080/exercices/emacs/{ids}?pretty=true&all=true&persp=true"
                # if problem:
                    # url += "&pb=true"

                # Perform GET request
                with urllib.request.urlopen(url) as response:
                    res_content = response.read().decode('utf-8')

                # 4. Split and Save content
                parts = res_content.split('###')

                # Ensure we have at least 3 parts
                while len(parts) < 3:
                    parts.append("")

                t_text = replace_dots(parts[0].strip("\n"))
                s_text = replace_dots(parts[1].strip("\n"))
                p_text = replace_dots(parts[2].strip("\n"))

                # Apply hierarchy depth replace if problem context
                if problem:
                    t_text = replace_problem_labels(t_text)
                    s_text = replace_problem_labels(s_text)
                    p_text = replace_problem_labels(p_text)

                base_filename = f"Ex {current_ex_num}"

                if problem:
                    save_split_content(t_text, paths['Text'], base_filename, False)
                else:
                    with open(os.path.join(paths['Text'], base_filename), 'w', encoding='utf-8') as f:
                        f.write(t_text)


                save_split_content(s_text, paths['Sol'], base_filename, problem)
                save_split_content(p_text, paths['Persp'], base_filename, problem)

                current_ex_num += 1

            except json.JSONDecodeError:
                print(f"Error decoding JSON in block: {json_str}")
            except Exception as e:
                print(f"Error processing block {ex_id if 'ex_id' in locals() else 'unknown'}: {e}")

if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("Usage: python script.py <Dir>")
        sys.exit(1)

    process_directory(sys.argv[1])
