#!/usr/bin/env python3
"""Clone a runtime scheduler fixture while patching TEST.ZTST in selected epochs.

This is a diagnostic fixture transform.  It leaves accepted generated assets
untouched, creates cheap local aliases for the shared RTL harness, and rewrites
only the selected feeder lists.

Usage: patch_runtime_sched_test.py OUT IN --epochs START:END --ztst N
"""
import os
import re
import shutil
import sys

ROOT=os.path.normpath(os.path.join(os.path.dirname(__file__),".."))
DATA=os.path.join(ROOT,"sim","data","top_psmct32_raster_demo")


def link_or_copy(src,dst):
    try: os.unlink(dst)
    except FileNotFoundError: pass
    try: os.link(src,dst)
    except OSError: shutil.copyfile(src,dst)


def read_table(tag):
    path=os.path.join(DATA,f"sh3_{tag}_epochs.txt")
    comments=[]; meta=None; rows=[]
    for line in open(path):
        if line.startswith("META "): meta=line.strip()
        elif line and line[0].isdigit(): rows.append(line.split())
        else: comments.append(line)
    if meta is None: raise ValueError(f"{path}: missing META")
    return comments,meta,rows


def patch_list(src,dst,ztst):
    lines=open(src).readlines(); word_lines=[]
    for i,line in enumerate(lines):
        s=line.strip()
        if s and not s.startswith("//"):
            word_lines.append(i)
    if len(word_lines)<4: raise ValueError(f"{src}: feeder list shorter than TEST header")
    li=word_lines[3]; test=int(lines[li].strip(),16)
    test=(test&~(3<<17))|((ztst&3)<<17)
    lines[li]=f"{test:016x}\n"
    with open(dst,"w") as f: f.writelines(lines)


def main(argv):
    if len(argv)<7 or argv[3]!="--epochs" or argv[5]!="--ztst":
        print(__doc__.strip()); return 2
    out,src_tag=argv[1],argv[2]
    a,b=argv[4].split(":",1); start=int(a); end=int(b); ztst=int(argv[6],0)
    if ztst not in range(4): raise ValueError("ZTST must be 0..3")
    comments,meta,rows=read_table(src_tag)
    if start<0 or end<start or end>len(rows):
        raise ValueError(f"invalid epoch slice {start}:{end} for {len(rows)} rows")

    out_rows=[]
    for row in rows:
        k=int(row[0]); old=list(row)
        tex_src=os.path.join(DATA,old[4]); list_src=os.path.join(DATA,old[8])
        tex_alias=f"sh3_{out}{k}_tex_lpddr.mem"
        list_alias=f"feeder_sh3_{out}{k}.mem"
        pal_alias=f"sh3_{out}{k}_pal.mem"
        link_or_copy(tex_src,os.path.join(DATA,tex_alias))
        if start<=k<end:
            patch_list(list_src,os.path.join(DATA,list_alias),ztst)
        else:
            link_or_copy(list_src,os.path.join(DATA,list_alias))
        if old[12]!="-":
            link_or_copy(os.path.join(DATA,old[12]),os.path.join(DATA,pal_alias))
        else:
            with open(os.path.join(DATA,pal_alias),"w") as f:
                f.write("// unused direct-color palette placeholder\n")
                f.writelines("00000000\n" for _ in range(256))
        old[4]=tex_alias; old[8]=list_alias
        old[12]=pal_alias if old[12]!="-" else "-"
        out_rows.append(old)

    with open(os.path.join(DATA,f"sh3_{out}_epochs.txt"),"w") as f:
        f.write(f"# diagnostic clone of {src_tag}: epochs {start}:{end} TEST.ZTST={ztst}\n")
        f.write("# k idx tbp cbp_reloc tex_file lpddr size crc list_file words records reuse pal_file pal_sum32\n")
        f.write(meta+"\n")
        for row in out_rows: f.write(" ".join(row)+"\n")

    params=open(os.path.join(DATA,f"sh3_{src_tag}_params.vh")).read()
    params=re.sub(r"^//.*\n",f"// diagnostic TEST.ZTST={ztst} clone of {src_tag}\n",params,count=1)
    with open(os.path.join(DATA,f"sh3_{out}_params.vh"),"w") as f: f.write(params)
    table=open(os.path.join(DATA,f"sh3_{src_tag}_epoch_table.vh")).read()
    with open(os.path.join(DATA,f"sh3_{out}_epoch_table.vh"),"w") as f: f.write(table)
    for stem in ("bios","payload"):
        link_or_copy(os.path.join(DATA,f"{stem}_sh3_{src_tag}.mem"),
                     os.path.join(DATA,f"{stem}_sh3_{out}.mem"))
    print(f"[patch_test] {src_tag} -> {out}: epochs {start}:{end} ZTST={ztst}; {len(rows)} total")
    return 0


if __name__=="__main__":
    raise SystemExit(main(sys.argv))
