"""Re-run one library asset with the operator's feedback: new version of the SAME id, authored by Astra in Blender.
usage: python3 tools/rerun.py <asset id> "<feedback>"   (prints the new version number on success)
Authored assets reuse their job (sheet, previous GLB + renders, script); imported ones get a fresh realistic concept
sheet from their card + the feedback, and the old thumbnail as 'what it was'."""
import json, os, shutil, subprocess, sys
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, os.path.join(ROOT, 'lib'))
import card as cardlib  # noqa: E402
NB = os.path.expanduser('~/forge-build/fge-look-hybrid/tools/rpg/look/nbpro.sh')
BUDGET = {'building': ('50k to 120k', 8), 'vehicle': ('40k to 110k', 8), 'prop': ('4k to 40k', 5), 'part': ('2k to 30k', 5),
          'weapon': ('40k to 90k', 6), 'monster': ('20k to 60k', 6)}


def frame_text(kind, cls, contract):
    if cls.startswith('vehicle.sea'):
        return 'Bow toward +Z, up = +Y, centred on X = 0; origin on the waterline plane at the middle of the hull length.'
    if contract.startswith('garage'):
        return ('Front toward +Z, up = +Y, +X = left side, centred on X = 0; origin on the ground midway between the axles. '
                'Wheels are separate meshes named Wheel_FL, Wheel_FR, Wheel_RL, Wheel_RR with their origin at the wheel centre.')
    if contract.startswith('weapon'):
        return 'Muzzle toward -Z, up = +Y, origin at the top-front of the grip.'
    return 'Front toward +Z, up = +Y, centred on X = 0 and Z = 0; origin on the ground at the centre of the footprint.'


def main(aid, feedback):
    allc = cardlib.load_all(ROOT)
    if aid not in allc:
        raise SystemExit(f'unknown asset {aid}')
    cur = cardlib.active(allc[aid]); ver = allc[aid][-1]['version'] + 1
    cls, slug = aid.split('/'); kind = cls.split('.')[0]
    if kind in ('character', 'motion') or cls.startswith('part.character'):
        raise SystemExit('characters are re-made by the Cast lane (rig + skins), not by this button')
    idx = {a['id']: a for a in json.load(open(f'{ROOT}/index.json'))['assets']}
    row = idx[aid]
    jd = f'{ROOT}/jobs/{slug}-v{ver}'
    os.makedirs(jd, exist_ok=True)
    prev_job = (cur.get('provenance') or {}).get('job')
    glb = cur['files']['glb'].split(':')[1]
    shutil.copyfile(f'{ROOT}/store/blobs/{glb}.glb', f'{jd}/previous.glb')
    if prev_job and os.path.exists(f'{ROOT}/jobs/{prev_job}/job.json'):
        j = json.load(open(f'{ROOT}/jobs/{prev_job}/job.json'))
        for f in ('sheet.jpg', 'final.png', f"build_{j['slug']}.py"):
            if os.path.exists(f'{ROOT}/jobs/{prev_job}/{f}'):
                shutil.copyfile(f'{ROOT}/jobs/{prev_job}/{f}', f'{jd}/{"previous_final.png" if f == "final.png" else f}')
        j['refs'] = [r for r in ('sheet.jpg', 'previous_final.png') if os.path.exists(f'{jd}/{r}')]
    else:
        s = row['size']
        size = f"about {s['w']:.2f} m wide (X), {s['l']:.2f} m long (Z), {s['h']:.2f} m high (Y)"
        thumb = f'{ROOT}/site/out/measure/thumbs/{glb}.jpg'
        if os.path.exists(thumb):
            shutil.copyfile(thumb, f'{jd}/previous.jpg')
        prompt = (f"Video game asset design turnaround plate, realistic, on a plain light grey background. {cur['name']}: {cur['summary']} "
                  f"Category: {cls.replace('.', ' ')}. Real size {size}. The art director asks: {feedback}. "
                  "Layout: big front view, side, top and back views, and a 3/4 hero view, callouts naming the parts and dimensions in "
                  "metres, material swatches. Rich real-world detail, believable wear. No brands, no text other than callouts.")
        subprocess.run([NB, f'{jd}/sheet.png', prompt, '--ar', '16:9', '--size', '2K'], check=True,
                       env={**os.environ, 'NBPRO_LEDGER': f'{ROOT}/jobs/provenance.jsonl'})
        from PIL import Image
        Image.open(f'{jd}/sheet.png').convert('RGB').save(f'{jd}/sheet.jpg', quality=88)
        tris, mats = BUDGET.get(kind, ('4k to 40k', 5))
        nodes = ', '.join(cur['nodes'].get('wheels') or []) if isinstance(cur.get('nodes'), dict) else ''
        j = {'name': f"{cur['name'].lower()} (the one on sheet.jpg, realistic)", 'title': cur['name'], 'size': size, 'tris': tris, 'mats': mats,
             'frame': frame_text(kind, cls, cur['frame'].get('contract', '')),
             'nodes': ('Keep these named wheel nodes: ' + nodes + '.') if nodes else '',
             'refs': ['sheet.jpg'] + (['previous.jpg'] if os.path.exists(f'{jd}/previous.jpg') else [])}
        if os.path.exists(f'{jd}/previous.jpg'):
            feedback += ' (previous.jpg shows the OLD version: keep its role and size, not its look.)'
    j.update(id=aid, slug=slug, version=ver, feedback=feedback, effort=j.get('effort', 'medium'))
    json.dump(j, open(f'{jd}/job.json', 'w'), indent=1)
    r = subprocess.run([f'{ROOT}/tools/author/launch.sh', jd])
    if r.returncode != 0 or not os.path.exists(f"{jd}/{slug}.glb"):
        raise SystemExit(f'Astra job failed (rc {r.returncode}); see jobs/{os.path.basename(jd)}/astra.log')
    subprocess.run([sys.executable, f'{ROOT}/tools/import_job.py', jd], check=True)
    print(ver)


if __name__ == '__main__':
    main(sys.argv[1], sys.argv[2])
