#!/usr/bin/env python3
"""Assemble the Bulgarian JELLY FUSION test set (Option C: 7 groups).

- Existing original tests are copied byte-for-byte (.in) and their .ans -> .sol.
- Boundary / structural fills are produced by gen.py and solved by the verified
  reference solver (markw) to produce .sol.
- Each test is validated against the global bounds and its subtask's structural
  guarantee. grade.properties is written with the Option-C groups/weights/deps.
"""
import os, subprocess, sys, shutil, random

ROOT = "/Users/deyanhadzhi-manich/Desktop/jelly_build"
SRC  = "/Users/deyanhadzhi-manich/Desktop/jellyfusion/data"
GEN  = os.path.join(ROOT, "testgen", "gen.py")
SOLVER = "/tmp/jf_mark"           # verified reference solver (markw)
TESTS = os.path.join(ROOT, "tests")
TASK = "jelly"

# ---- Option C manifest: ordered list of groups; each entry is
#   ("copy", "<sample|secret>/<name>")  or  ("gen", cat, N, seed, *extra)
GROUPS = [
    # G0: samples (0 pts)
    ("samples", 0, "", [
        ("copy", "sample/1"), ("copy", "sample/2"),
        ("copy", "sample/3"), ("copy", "sample/4"),
    ]),
    # G1: N <= 20  (brute force)
    ("N<=20", 10, "", [
        ("copy","secret/036-one"), ("copy","secret/002-random"),
        ("copy","secret/003-random"), ("copy","secret/004-random"),
        ("copy","secret/007-random_digitlength"), ("copy","secret/012-handmade"),
        ("gen","random",20,101), ("gen","alt",20,102), ("gen","digitlength",18,103),
        ("gen","smallint",15,104), ("gen","maxalt",20,105), ("gen","sorted",17,106),
        ("gen","biggaps",20,107,5), ("gen","monotone",20,108), ("gen","random",13,109),
    ]),
    # G2: N <= 500  (O(N^2))
    ("N<=500", 12, "1", [
        ("copy","secret/015-random_smallint"),
        ("gen","random",500,201), ("gen","digitlength",500,202), ("gen","smallint",500,203),
        ("gen","alt",499,204), ("gen","sorted",500,205), ("gen","sorted_xy",400,206),
        ("gen","spiky",500,207,40), ("gen","biggaps",500,208,12), ("gen","onlyhull",500,209),
        ("gen","maxalt",500,210), ("gen","random",250,211), ("gen","digitlength",120,212),
    ]),
    # G3: N <= 4000  (O(N^2))
    ("N<=4000", 15, "1-2", [
        ("copy","secret/005-random"), ("copy","secret/008-random_digitlength"),
        ("copy","secret/010-random_sorted"), ("copy","secret/013-gen_left"),
        ("gen","random",4000,301), ("gen","digitlength",4000,302), ("gen","alt",4000,303),
        ("gen","sorted",3500,304), ("gen","sorted_xy",3000,305), ("gen","spiky",4000,306,35),
        ("gen","biggaps",4000,307,102), ("gen","onlyhull",4000,308), ("gen","maxalt",4000,309),
        ("gen","smallint",4000,310), ("gen","random",2500,311),
    ]),
    # G4: one dimension constant (foothold)  -- standalone
    ("const-dim", 8, "", [
        ("gen","constw",300000,401), ("gen","consth",300000,402), ("gen","constw",150000,403),
        ("gen","consth",100000,404), ("gen","constw",50000,405), ("gen","consth",1000,406),
        ("gen","constw",20,407), ("gen","consth",5,408),
        ("gen","constw",300000,409,1), ("gen","constw",300000,410,1000000),
    ]),
    # G5: h non-decreasing AND w non-increasing (CHT)  -- standalone
    ("monotone", 20, "", [
        ("gen","monotone",300000,501), ("gen","monotone",300000,502), ("gen","monotone",200000,503),
        ("gen","monotone",100000,504), ("gen","monotone",50000,505), ("gen","monotone",5000,506),
        ("gen","monotone",500,507), ("gen","monotone",50,508), ("gen","monotone",20,509),
        ("gen","monotone",299999,510), ("gen","monotone",150000,511), ("gen","monotone",2,512),
    ]),
    # G6: full N <= 3e5  (all the large originals, used exactly)  -- depends on all
    ("full", 35, "1-5", [
        ("copy", f"secret/{name}") for name in [
            "001-random_digitlength","006-random","009-random_digitlength","011-random_sorted",
            "014-gen_left","016-random_smallint","017-spiky","018-spiky","019-spiky",
            "020-biggaps","021-biggaps","022-biggaps","023-biggaps","024-biggaps","025-biggaps",
            "026-biggaps","027-biggaps","028-biggaps","029-biggaps","030-maxans","031-maxalt",
            "032-random_alt","033-random_sorted_xy","034-decreasing","035-increasing","037-onlyhull",
        ]
    ]),
]

VMAX, NMAX = 10**6, 300000

def read_input(text):
    toks = text.split()
    n = int(toks[0]); P=[]
    idx=1
    for _ in range(n):
        P.append((int(toks[idx]), int(toks[idx+1]))); idx+=2
    return n, P

def validate(n, P, group_name):
    assert 1 <= n <= NMAX, f"N out of range: {n}"
    assert len(P)==n, "pair count mismatch"
    for h,w in P:
        assert 1<=h<=VMAX and 1<=w<=VMAX, f"value out of range: {h},{w}"
    if group_name=="N<=20":      assert n<=20
    elif group_name=="N<=500":   assert n<=500
    elif group_name=="N<=4000":  assert n<=4000
    elif group_name=="const-dim":
        allw = len(set(w for _,w in P))==1
        allh = len(set(h for h,_ in P))==1
        assert allw or allh, "const-dim: neither dimension constant"
    elif group_name=="monotone":
        hs=[h for h,_ in P]; ws=[w for _,w in P]
        assert all(hs[i]<=hs[i+1] for i in range(n-1)), "monotone: h not non-decreasing"
        assert all(ws[i]>=ws[i+1] for i in range(n-1)), "monotone: w not non-increasing"

def main():
    if os.path.isdir(TESTS): shutil.rmtree(TESTS)
    os.makedirs(TESTS)
    assert os.path.exists(SOLVER), "build /tmp/jf_mark first"
    idx=0
    ranges=[]; weights=[]; deps=[]; report=[]
    for gname, weight, dep, entries in GROUPS:
        start = idx+1
        for e in entries:
            idx+=1
            stem = f"{TASK}.{idx:03d}"
            if e[0]=="copy":
                src = os.path.join(SRC, e[1])
                intext = open(src+".in").read()
                sol = open(src+".ans").read().strip()+"\n"
                origin = "copy "+e[1]
            else:
                _,cat,N,seed,*extra = e
                args=[sys.executable,GEN,cat,str(N),str(seed)]+[str(x) for x in extra]
                intext = subprocess.run(args,capture_output=True,text=True,check=True).stdout
                sol = subprocess.run([SOLVER],input=intext,capture_output=True,text=True,check=True).stdout.strip()+"\n"
                origin = f"gen {cat} N={N} seed={seed}"+(f" {extra}" if extra else "")
            n,P = read_input(intext)
            validate(n,P,gname)
            open(os.path.join(TESTS,stem+".in"),"w").write(intext if intext.endswith("\n") else intext+"\n")
            open(os.path.join(TESTS,stem+".sol"),"w").write(sol)
            report.append((idx,gname,n,origin,sol.strip()))
        ranges.append(f"{start}-{idx}")
        weights.append(weight); deps.append(dep)

    # grade.properties
    gp = (f"time=3\nmemory=256\nio_time=15\ncompile_time=15\n"
          f"groups={','.join(ranges)}\n"
          f"weights={','.join(map(str,weights))}\n"
          f"dependencies={','.join(deps)}\n")
    open(os.path.join(ROOT,"grade.properties"),"w").write(gp)

    # report
    print("idx  group        N        answer                origin")
    for i,g,n,o,a in report:
        print(f"{i:>3}  {g:<11} {n:>7}  {a:>20}  {o}")
    print("\n--- grade.properties ---\n"+gp)
    print(f"Total tests: {idx}  | groups: {len(ranges)}  | weights sum: {sum(weights)}")

if __name__=="__main__":
    main()
