from .parser import parse_patch_file

from pathlib import Path

from task.util import *

def resolve_position(location, src: str):
    if location["type"] == "char":
        return location["index"]
    elif location["type"] == "lncol":
        j = 0
        for i, x in enumerate(src.split('\n')):
            if (i+1) == location["line"]:
                if location["column"] > len(x):
                    print(f"Cannot insert at line {location['line']} column {location['column']}. The line is not that long.")
                    exit(-1)
                return j + location["column"]
            j += len(x) + 1
            
        print(f"Cannot insert at line {location['line']}. The file is not long enough.")
        exit(-1)

def read_insertion(action, src):
    position = resolve_position(action["at"], src)
    return {"content": action["content"], "pos": position}

def process_patch_file(patch_file: str, check_date: bool = True):
    patches = parse_patch_file(patch_file)
    
    for patch in patches:
        target_src = EXTRACTED_DIR / patch["target"]
        target_dest = PATCHED_RSC_DIR / patch["target"]
        
        # Skip old patches
        if check_date and target_dest.exists() and target_dest.stat().st_mtime > patch["timestamp"]:
            print(f"Skipping patch {patch['target']}...")
            continue
        
        print(f"Patching {patch['target']} with {len(patch['actions'])} actions")
        
        # Read the source of the file
        with open(target_src, 'r') as f:
            src = f.read()
            
        # Resolve the actual char locations in the patches
        insertions = [read_insertion(action, src) for action in patch["actions"]]
        insertions = [x for x in insertions if x is not None]
        
        for insertion in insertions:
            src = src[:insertion["pos"]] + insertion["content"] + src[insertion["pos"]:]

            # Correct insertions that follow this one
            for i2 in insertions:
                # Only update insertions that come *after* this one
                if i2 == insertion or i2["pos"] < insertion["pos"]:
                    continue
                
                i2["pos"] += len(insertion["content"])
                
        # Write the changed output
        with open(target_dest, 'w') as f:
            f.write(src)
            
def process_all_patches(dir: Path | str, check_date: bool = True):
    dir = Path(dir)
    
    for (cd, _, files) in dir.walk():
        for f in files:
            if f.endswith(".patch"):
                print("Processing patch {}".format((cd / f).relative_to(dir)))
                process_patch_file(str(cd / f), check_date=check_date)