"""Prepare original native timeline bytes, including exact Metal mip levels.
Usage: python3 scripts/native-ui/export-timeline-materials.py NATIVE_REPO
Requires macOS/Metal for offline export only. Does not modify native themes.
"""
from pathlib import Path
import hashlib, json, plistlib, struct, subprocess, sys, tempfile
from timeline_webp import encode
root = Path(__file__).resolve().parents[2]
native = Path(sys.argv[1])
output = root / 'content-assets/test-content/timeline-materials'
output.mkdir(parents=True, exist_ok=True)
manifest = {}
rgba = lambda c: [c[k] for k in ('red', 'green', 'blue', 'alpha')]
rect = lambda r: [r[k] for k in ('x', 'y', 'width', 'height')]
with tempfile.TemporaryDirectory(prefix='y2k-timeline-export-') as folder:
    temp = Path(folder)
    subprocess.run(['xcrun', 'swiftc', str(Path(__file__).with_name('prepare-timeline-atlas.swift')), '-o', str(temp / 'prepare')], check=True)
    for mode, identity in [('light','np24-01-pearl-quilt'),('frosted','np24-03-frosted-stars'),('dark','np24-15-midnight-tartan')]:
        source = (native / 'Sources/Y2KUI/Themes/Bundled' / (identity + '.y2ktheme')).read_bytes()
        theme = plistlib.loads(source); atlas = theme['timeline']
        if theme['version'] != 3: raise ValueError('Export requires a migrated single-profile theme')
        (temp / 'atlas.png').write_bytes(theme['assets'][atlas['image']])
        subprocess.run([str(temp / 'prepare'), str(temp / 'atlas.png'), str(temp)], check=True)
        levels = json.loads((temp / 'levels.json').read_text())
        pixels = (temp / 'pixels.bin').read_bytes()
        (temp / 'gloss.png').write_bytes(theme['assets'][atlas['glossProfile']])
        subprocess.run([str(temp / 'prepare'),str(temp / 'gloss.png'),str(temp)],check=True)
        gloss_levels=json.loads((temp / 'levels.json').read_text()); gloss_pixels=(temp / 'pixels.bin').read_bytes()
        assert gloss_levels[0]['width']==1 and gloss_levels[0]['height']==128
        values = [atlas['radius'],atlas['period'],int(atlas['stepMarks']),3,*rect(atlas['scrubber']),0,0,0,0]
        for i, slot in enumerate(atlas['slots']):
            values += [*rect(slot['pattern']),*rect(slot['backing']),0,0,0,0,*rgba(theme['palette'][i])[:3],slot['opacity']]
        # Compile the same resolved component records as ThemeAssets.prepare.
        styles = theme['trackStyles']
        if len(styles) != 7: raise ValueError('Expected seven component style pairs')
        for pair in styles:
            for style in [pair['headerStyle'],pair['washiStyle']]:
                if 'gloss' in style: raise ValueError('Height variants are retired')
                values += [style['radius'],style['period'],int(style['glossEnabled']),0,style['glossStrength'],style['backingOpacity'],int(style['glossOnFlat']),int('pattern' in style)]
                values += rect(style['pattern']) if 'pattern' in style else [0]*4
        uniforms = struct.pack('<292f',*values)
        assert len(uniforms)==1168
        payload = uniforms + pixels + gloss_pixels
        compressed, levels, gloss_levels = encode(levels, pixels, gloss_levels, gloss_pixels)
        digest = hashlib.sha256(compressed).hexdigest()
        (output / (digest + '.webp')).write_bytes(compressed)
        manifest[mode] = dict(id=identity, sourceSHA256=hashlib.sha256(source).hexdigest(),
            url='/test-content/timeline-materials/'+digest+'.webp', sha256=digest,
            bytes=len(compressed), transport='webp-mips-v1', imageWidth=769, imageHeight=256, imageDecodedBytes=769*256*4, uniforms=list(struct.unpack('<292f',uniforms)), pixelSHA256={'levels':hashlib.sha256(pixels).hexdigest(),'glossLevels':hashlib.sha256(gloss_pixels).hexdigest()}, decodedBytes=len(payload), uniformBytes=len(uniforms), layoutVersion=3, glossOffset=len(uniforms)+len(pixels), glossLevels=gloss_levels, styles=[{role:{k:v for k,v in style.items() if k != 'gloss'} for role,style in pair.items()} for pair in styles], levels=levels,
            palette=[rgba(c) for c in theme['palette']], textInk=rgba(theme['inks']['text']),
            fallbackTextInk=[.1,.12,.15,1], period=atlas['period'])
(root / 'web/animator/timeline-materials.generated.js').write_text('// Generated from original native themes by export-timeline-materials.py.\nexport const timelineMaterials = '+json.dumps(manifest,separators=(',',':'))+';\n')
print(json.dumps({k:{'compressed':v['bytes'],'decoded':v['decodedBytes']} for k,v in manifest.items()},indent=2))
