#!/usr/bin/env python3
import argparse, os, subprocess, sys
from pathlib import Path

DIR = Path(__file__).resolve().parent

STYLE_PRESETS = {
    'classic': {
        'u_motion1':'0.185,0.118,0.52,0.185',
        'u_motion2':'1.55,0.12,0.00,0.0',
        'u_motion3':'0.92,1.08,2.0,0.55',
        'u_motion4':'8.0,11.0,0.35,0.18',
        'u_motion5':'0.26,0.42,0.13,0.0',
        'u_top_color':'0.30,0.95,0.90', 'u_mid_color':'0.96,1.00,1.00', 'u_bottom_color':'0.55,0.32,0.96',
        'u_outline_color':'0.96,1.00,1.00', 'u_shadow_color':'0.08,0.00,0.18', 'u_background_color':'0.00,0.00,0.02',
    },
    'purple': {
        'u_motion1':'0.180,0.118,0.52,0.170', 'u_motion2':'1.52,0.10,0.00,0.0', 'u_motion3':'0.92,1.08,2.0,0.62',
        'u_motion4':'8.0,11.0,0.30,0.18', 'u_motion5':'0.28,0.46,0.13,0.0',
        'u_top_color':'0.78,0.78,1.00', 'u_mid_color':'1.00,0.96,1.00', 'u_bottom_color':'0.56,0.26,0.92',
        'u_outline_color':'1.00,1.00,1.00', 'u_shadow_color':'0.06,0.00,0.14', 'u_background_color':'0.00,0.00,0.03',
    },
    'copper': {
        'u_motion1':'0.170,0.118,0.54,0.140', 'u_motion2':'1.34,0.08,0.00,0.0', 'u_motion3':'0.91,1.10,2.0,0.50',
        'u_motion4':'8.0,12.0,0.32,0.08', 'u_motion5':'0.24,0.38,0.11,0.0',
        'u_top_color':'0.80,0.42,0.08', 'u_mid_color':'1.00,0.85,0.34', 'u_bottom_color':'0.62,0.22,0.02',
        'u_outline_color':'1.00,0.92,0.72', 'u_shadow_color':'0.10,0.02,0.00', 'u_background_color':'0.01,0.00,0.00',
    },
    'ice': {
        'u_motion1':'0.160,0.120,0.50,0.205', 'u_motion2':'1.30,0.14,0.50,0.0', 'u_motion3':'0.94,1.10,2.2,0.85',
        'u_motion4':'8.0,12.0,0.20,0.30', 'u_motion5':'0.30,0.48,0.10,0.0',
        'u_top_color':'0.18,0.62,0.95', 'u_mid_color':'0.91,1.00,1.00', 'u_bottom_color':'0.13,0.18,0.75',
        'u_outline_color':'0.68,0.94,1.00', 'u_shadow_color':'0.00,0.03,0.16', 'u_background_color':'0.000,0.003,0.014',
    },
}
MOTION_PRESETS = {
    'balanced': {'u_motion1':'0.185,0.118,0.52,0.185','u_motion2':'1.55,0.12,0.00,0.0','u_motion3':'0.92,1.08,2.0,0.55','u_motion4':'8.0,11.0,0.35,0.18','u_motion5':'0.26,0.42,0.13,0.0'},
    'subtle': {'u_motion1':'0.135,0.105,0.56,0.105','u_motion2':'1.20,0.06,0.00,0.0','u_motion3':'0.94,1.10,2.0,0.55','u_motion4':'8.0,11.0,0.35,0.18','u_motion5':'0.24,0.42,0.13,0.0'},
    'big': {'u_motion1':'0.155,0.155,0.53,0.170','u_motion2':'1.35,0.10,0.00,0.0','u_motion3':'0.88,1.12,2.0,0.55','u_motion4':'8.0,11.0,0.35,0.18','u_motion5':'0.26,0.42,0.13,0.0'},
    'fast': {'u_motion1':'0.300,0.112,0.51,0.170','u_motion2':'1.75,0.14,0.00,0.0','u_motion3':'0.92,1.06,2.0,0.55','u_motion4':'8.0,11.0,0.35,0.18','u_motion5':'0.24,0.42,0.13,0.0'},
    'wild': {'u_motion1':'0.235,0.126,0.50,0.245','u_motion2':'2.10,0.26,0.20,0.0','u_motion3':'0.90,1.04,2.0,0.55','u_motion4':'8.0,11.0,0.35,0.18','u_motion5':'0.22,0.42,0.13,0.0'},
    'top': {'u_motion1':'0.180,0.115,0.28,0.135','u_motion2':'1.45,0.10,0.00,0.0','u_motion3':'0.92,1.08,2.0,0.55','u_motion4':'8.0,11.0,0.35,0.18','u_motion5':'0.24,0.42,0.13,0.0'},
    'giant': {'u_motion1':'0.135,0.205,0.53,0.140','u_motion2':'1.12,0.08,0.00,0.0','u_motion3':'0.84,1.16,2.0,0.55','u_motion4':'8.0,11.0,0.35,0.18','u_motion5':'0.28,0.42,0.13,0.0'},
    'tiny-fast': {'u_motion1':'0.355,0.082,0.56,0.105','u_motion2':'1.95,0.16,0.00,0.0','u_motion3':'0.98,1.03,2.0,0.55','u_motion4':'8.0,11.0,0.35,0.18','u_motion5':'0.22,0.42,0.13,0.0'},
    'mega-wave': {'u_motion1':'0.205,0.120,0.50,0.300','u_motion2':'1.70,0.30,0.16,0.0','u_motion3':'0.91,1.05,2.0,0.55','u_motion4':'8.0,11.0,0.35,0.18','u_motion5':'0.24,0.42,0.13,0.0'},
    'lowline': {'u_motion1':'0.175,0.116,0.72,0.120','u_motion2':'1.40,0.08,0.00,0.0','u_motion3':'0.92,1.08,2.0,0.55','u_motion4':'8.0,11.0,0.35,0.18','u_motion5':'0.24,0.42,0.13,0.0'},
    'centered': {'u_motion1':'0.180,0.118,0.50,0.160','u_motion2':'1.50,0.10,0.00,0.0','u_motion3':'0.92,1.08,2.0,0.55','u_motion4':'8.0,11.0,0.35,0.18','u_motion5':'0.26,0.42,0.13,0.0'},
}
SCENE_PRESETS = {
    **{k: {**STYLE_PRESETS[k], **MOTION_PRESETS['balanced']} for k in ['classic','purple','copper','ice']},
    **{k: {**STYLE_PRESETS['classic'], **MOTION_PRESETS[k]} for k in ['subtle','big','fast','wild','top','giant','tiny-fast','mega-wave','lowline','centered']},
    'copper-bars': {
        **STYLE_PRESETS['copper'],
        'u_motion1':'0.165,0.128,0.58,0.115','u_motion2':'1.25,0.05,0.00,0.0','u_motion3':'0.90,1.10,2.0,0.46','u_motion4':'8.0,11.0,0.58,0.08','u_motion5':'0.34,0.52,0.13,0.0',
    },
    'deep-space': {
        **STYLE_PRESETS['ice'],
        'u_motion1':'0.170,0.122,0.48,0.190','u_motion2':'1.42,0.14,0.50,0.0','u_motion3':'0.92,1.09,2.2,0.78','u_motion4':'8.0,12.0,0.28,0.36','u_motion5':'0.38,0.60,0.10,0.0',
        'u_top_color':'0.58,0.92,1.00','u_mid_color':'0.95,0.98,1.00','u_bottom_color':'0.24,0.12,0.72','u_outline_color':'0.76,0.88,1.00','u_shadow_color':'0.010,0.010,0.080','u_background_color':'0.000,0.000,0.012',
    },
}

ALPHABET = {' ':0}
for i,ch in enumerate('ABCDEFGHIJKLMNOPQRSTUVWXYZ', start=1): ALPHABET[ch]=i
for i,ch in enumerate('0123456789', start=27): ALPHABET[ch]=i
for i,ch in enumerate(['.',',',':',';','!','?','-','+','=','*','/','\\','(',')','[',']','<','>','#','@','&','%','$','_','\'','"','|'], start=37): ALPHABET[ch]=i

def translit(text):
    repl = {'ä':'AE','ö':'OE','ü':'UE','ß':'SS','Ä':'AE','Ö':'OE','Ü':'UE','é':'E','è':'E','ê':'E','á':'A','à':'A','ó':'O','ò':'O','í':'I','ì':'I','ç':'C'}
    for a,b in repl.items(): text = text.replace(a,b)
    return text.upper()[:512]

def encode_text(text):
    text = translit(text)
    lines = [f'u_text_length={len(text)}']
    chars = [ALPHABET.get(ch, 42) for ch in text]
    chars += [0] * (512 - len(chars))
    for block in range(32):
        comps = []
        base = block*16
        for comp in range(4):
            packed = 0
            for slot in range(4):
                packed |= (chars[base + comp*4 + slot] & 63) << (slot*6)
            comps.append(str(packed))
        lines.append(f'u_text{block:02d}=' + ','.join(comps))
    return lines

def list_presets():
    print('Color presets:')
    for k in STYLE_PRESETS: print(' ', k)
    print('\nMotion presets:')
    for k in MOTION_PRESETS: print(' ', k)
    print('\nScene presets:')
    for k in SCENE_PRESETS: print(' ', k)

def parse_motion_tuple(v):
    return [x.strip() for x in v.split(',')]

def main():
    argv = sys.argv[1:]
    passthrough = []
    if '--' in argv:
        idx = argv.index('--')
        passthrough = argv[idx+1:]
        argv = argv[:idx]
    ap = argparse.ArgumentParser(add_help=False)
    ap.add_argument('-p','--preset', default='classic')
    ap.add_argument('-m','--motion', default='')
    ap.add_argument('-s','--scene', default='')
    ap.add_argument('--list-presets', action='store_true')
    ap.add_argument('--speed')
    ap.add_argument('--height')
    ap.add_argument('--amplitude')
    ap.add_argument('--y')
    ap.add_argument('--waves')
    ap.add_argument('--letter-spacing')
    ap.add_argument('--gap')
    ap.add_argument('--harmonic')
    ap.add_argument('--phase')
    ap.add_argument('--align-to-wave')
    ap.add_argument('--outline')
    ap.add_argument('--shadow-x')
    ap.add_argument('--shadow-y')
    ap.add_argument('--glow')
    ap.add_argument('--scanlines')
    ap.add_argument('--stars')
    ap.add_argument('--shine')
    ap.add_argument('--shine-speed')
    ap.add_argument('--source-mix')
    ap.add_argument('--fps', default='60')
    ap.add_argument('--wallpaperd', default=os.environ.get('HYPRTILE_WALLPAPERD','hyprtile-wallpaperd'))
    ap.add_argument('--params-out')
    ap.add_argument('-h','--help', action='help')
    ap.add_argument('text', nargs='*')
    args = ap.parse_args(argv)
    if args.list_presets:
        list_presets(); return 0

    text = ' '.join(args.text).strip() or 'HYPRTILE - AMIGA SINUS SCROLLER ONLINE!'

    if args.scene:
        if args.scene not in SCENE_PRESETS:
            print(f'Unknown scene preset: {args.scene}', file=sys.stderr); return 2
        settings = dict(SCENE_PRESETS[args.scene])
    else:
        if args.preset not in STYLE_PRESETS:
            print(f'Unknown color preset: {args.preset}', file=sys.stderr); return 2
        settings = dict(STYLE_PRESETS[args.preset])
        motion = args.motion or 'balanced'
        if motion not in MOTION_PRESETS:
            print(f'Unknown motion preset: {motion}', file=sys.stderr); return 2
        settings.update(MOTION_PRESETS[motion])

    m1 = parse_motion_tuple(settings['u_motion1'])
    m2 = parse_motion_tuple(settings['u_motion2'])
    m3 = parse_motion_tuple(settings['u_motion3'])
    m4 = parse_motion_tuple(settings['u_motion4'])
    m5 = parse_motion_tuple(settings['u_motion5'])

    if args.speed is not None: m1[0] = args.speed
    if args.height is not None: m1[1] = args.height
    if args.y is not None: m1[2] = args.y
    if args.amplitude is not None: m1[3] = args.amplitude
    if args.waves is not None: m2[0] = args.waves
    if args.harmonic is not None: m2[1] = args.harmonic
    if args.phase is not None: m2[2] = args.phase
    if args.align_to_wave is not None: m2[3] = args.align_to_wave
    if args.letter_spacing is not None: m3[0] = args.letter_spacing
    if args.gap is not None: m3[1] = args.gap
    if args.outline is not None: m3[2] = args.outline
    if args.glow is not None: m3[3] = args.glow
    if args.shadow_x is not None: m4[0] = args.shadow_x
    if args.shadow_y is not None: m4[1] = args.shadow_y
    if args.scanlines is not None: m4[2] = args.scanlines
    if args.stars is not None: m4[3] = args.stars
    if args.source_mix is not None: m5[0] = args.source_mix
    if args.shine is not None: m5[1] = args.shine
    if args.shine_speed is not None: m5[2] = args.shine_speed

    settings['u_motion1'] = ','.join(m1)
    settings['u_motion2'] = ','.join(m2)
    settings['u_motion3'] = ','.join(m3)
    settings['u_motion4'] = ','.join(m4)
    settings['u_motion5'] = ','.join(m5)

    lines = ['# HyprTile Amiga Sine Scroller (grouped params, 64-safe)']
    for k in ['u_motion1','u_motion2','u_motion3','u_motion4','u_motion5','u_top_color','u_mid_color','u_bottom_color','u_outline_color','u_shadow_color','u_background_color']:
        lines.append(f'{k}={settings[k]}')
    lines.extend(encode_text(text))

    out_path = Path(args.params_out) if args.params_out else Path(os.environ.get('XDG_RUNTIME_DIR','/tmp')) / 'hyprtile-sinus-scroller.params'
    out_path.write_text('\n'.join(lines) + '\n', encoding='utf-8')
    if args.params_out:
        print(str(out_path)); return 0

    cmd = [args.wallpaperd, '--backend','gl','--shader', str(DIR/'hyprtile-sinus-scroller.frag'), '--params', str(out_path), '--fps', str(args.fps)] + passthrough
    return subprocess.call(cmd)

if __name__ == '__main__':
    raise SystemExit(main())
