"""Render a small scientific SVG from measured morphology pixels and model offsets."""
import base64
import math
import struct
import zlib
from comet_orbits import inverse_cd

def grayscale_png(values):
    height, width = len(values), len(values[0])
    raw = bytearray()
    for row in reversed(values):
        raw.append(0)
        for value in row:
            intensity = 0 if value is None else round(255*math.log1p(max(0,value)*100)/math.log1p(450))
            raw.append(max(0,min(255,intensity)))
    def chunk(kind,content):
        return struct.pack('>I',len(content))+kind+content+struct.pack('>I',zlib.crc32(kind+content)&0xffffffff)
    return b'\x89PNG\r\n\x1a\n'+chunk(b'IHDR',struct.pack('>IIBBBBB',width,height,8,0,0,0,0))+chunk(b'IDAT',zlib.compress(bytes(raw)))+chunk(b'IEND',b'')

def write_figure(path, image, results):
    width,height = image['processing']['width'],image['processing']['height']
    zoom,left,top = 2,42,43
    panel_width,panel_height = width*zoom,height*zoom
    x0,y0 = results['imageNucleusBlock']
    def projected(x,y):
        return left+x*zoom,top+(height-1-y)*zoom
    centre = projected(x0,y0)
    png = base64.b64encode(grayscale_png(image['values'])).decode()
    lines = [f'<svg xmlns="http://www.w3.org/2000/svg" width="340" height="440" viewBox="0 0 340 440">',
      '<rect width="340" height="440" fill="#071522"/>',
      '<style>text{font-family:system-ui,sans-serif;font-size:11px;fill:#d6e8f3} .title{font-size:13px;font-weight:600}</style>',
      '<text class="title" x="16" y="21">ISON, HST F606W, 2013-04-10</text>',
      f'<image x="{left}" y="{top}" width="{panel_width}" height="{panel_height}" href="data:image/png;base64,{png}"/>',
      f'<rect x="{left}" y="{top}" width="{panel_width}" height="{panel_height}" fill="none" stroke="#617e91"/>']
    for beta,color in [(0.005,'#f6d78c'),(0.03,'#78e0da'),(0.1,'#bdadff')]:
        records = sorted([row for row in results['modelPoints'] if row['beta']==beta and row['ageDays']<=120],key=lambda row:row['ageDays'])
        points = [centre]+[projected(x0+row['blockOffset'][0],y0+row['blockOffset'][1]) for row in records]
        path_data = ' '.join(('M' if index==0 else 'L')+f'{x:.3f},{y:.3f}' for index,(x,y) in enumerate(points))
        lines.append(f'<path d="{path_data}" fill="none" stroke="{color}" stroke-width="1.5" clip-path="url(#panel)"/>')
    lines.append(f'<defs><clipPath id="panel"><rect x="{left}" y="{top}" width="{panel_width}" height="{panel_height}"/></clipPath></defs>')
    def arrow(delta,color,label,label_x,label_y):
        length = math.hypot(*delta)
        x=centre[0]+delta[0]/length*46
        y=centre[1]-delta[1]/length*46
        lines.extend([f'<line x1="{centre[0]}" y1="{centre[1]}" x2="{x}" y2="{y}" stroke="{color}" stroke-width="1.3"/>',f'<circle cx="{x}" cy="{y}" r="2.2" fill="{color}"/>',f'<text x="{label_x}" y="{label_y}" style="fill:{color}">{label}</text>'])
    for angle,color,label,label_y in [(results['reference']['antisolarPaDegrees'],'#ff958e','Antisolar',350),(results['reference']['negativeVelocityPaDegrees'],'#92bdff','Opposite velocity',366)]:
        radians=math.radians(angle)
        offset=inverse_cd(image['wcs'],[math.sin(radians),math.cos(radians)])
        arrow(offset,color,label,16,label_y)
    for direction,label in [([0,1],'N'),([1,0],'E')]:
        vector=inverse_cd(image['wcs'],direction)
        length=math.hypot(*vector)
        x=left+panel_width-28;y=top+28
        end_x=x+vector[0]/length*20;end_y=y-vector[1]/length*20
        lines += [f'<line x1="{x}" y1="{y}" x2="{end_x}" y2="{end_y}" stroke="white"/>',f'<text x="{end_x-3}" y="{end_y-5}">{label}</text>']
    scale_width = 5/(math.hypot(image['wcs']['CD1_1'],image['wcs']['CD2_1'])*3600*8)*zoom
    lines += [f'<line x1="{left+panel_width-14-scale_width}" y1="{top+panel_height-14}" x2="{left+panel_width-14}" y2="{top+panel_height-14}" stroke="white" stroke-width="2"/>',f'<text x="{left+panel_width-57}" y="{top+panel_height-22}">5 arcsec</text>']
    lines += ['<text x="16" y="331">Force ratio</text>', '<text x="120" y="331" style="fill:#f6d78c">0.005</text>', '<text x="202" y="331" style="fill:#78e0da">0.03</text>', '<text x="276" y="331" style="fill:#bdadff">0.1</text>', '<text x="16" y="386">Curves: solar relative-release model</text>',
              '<text x="16" y="402">Pixels: measured HST, median / log display</text>',
              '<text x="16" y="420">HST / MAST, program 13198, J.-Y. Li</text>','</svg>']
    path.write_text('\n'.join(lines)+'\n')
