"""Copy verified original galaxy UI frames; no tracing, recolouring or redrawing."""
import hashlib
import json
import xml.etree.ElementTree as ET
from pathlib import Path
from PIL import Image

root=Path('artifacts/galaxy-marker-research')
out=Path('XFEEDToolBox/Assets/GalaxyIcons')
out.mkdir(exist_ok=True)
icons=[]
current=[]
dependencies=json.loads((root/'map-bitmap-dependencies.json').read_text())
if not dependencies['allDependenciesResolved'] or dependencies['unknown']:
    raise ValueError('Current map icon bitmap dependencies are incomplete')


def copy(key,source,resource,sprite,frame,label,note=None):
    data=source.read_bytes()
    if source.suffix=='.svg':
        svg=ET.fromstring(data)
        if any(x.tag.endswith('}image') or any('bitmap' in k.lower() for k in x.attrib) for x in svg.iter()):
            raise ValueError('Unresolved original bitmap dependency: '+key)
        if not any(x.tag.endswith('}path') for x in svg.iter()):
            raise ValueError('Missing original vector geometry: '+key)
    path=out/(key+source.suffix)
    path.write_bytes(data)
    row=dict(key=key,file=path.name,resource=resource,spriteId=sprite,frame=frame,label=label,
             sha256=hashlib.sha256(data).hexdigest(),exportBytesUnchanged=True)
    if note:row['note']=note
    icons.append(row)


bookmarks=[('Planet',1,'planet'),('System',11,'system'),('Coriolis',21,'station_coriolis'),
           ('Bernal',31,'station_bernal'),('Orbis',41,'station_orbis'),('Outpost',51,'station_outpost'),
           ('SurfacePort',61,'surface_port'),('SurfaceSettlement',71,'surface_settlement'),
           ('LandablePlanet',81,'planet_landable'),('Default',91,'default'),('Star',101,'star'),
           ('Asteroid',111,'asteroid'),('DockableMegaship',121,'megaShip_dockable'),
           ('UndockableMegaship',130,'megaShip_undockable'),('Installation',140,'installation')]
for name,frame,label in bookmarks:
    copy('Bookmark'+name,root/'ui-svg/DefineSprite_304_BookmarkButtonIcon'/f'{frame}.svg','ui',304,frame,label)
for key,sprite,name in [('TabBookmarks',251,'TabIconBookmarks'),('SelectedDestination',289,'NavMarkerIconSelected'),('CurrentLocation',291,'NavMarkerIconCurrent')]:
    copy(key,root/f'ui-svg/DefineSprite_{sprite}_{name}/1.svg','ui',sprite,1,name)
for key,frame,label in [('Focus',9,'focused'),('Selection',19,'selection'),('Location',29,'location'),('ConflictZones',39,'conflictZones'),('Taxi',49,'taxi'),
                        ('FocusThin',58,'focusedThin'),('SelectionThin',68,'selectionThin'),('LocationThin',78,'locationThin'),('ConflictZonesThin',88,'conflictZonesThin'),('TaxiThin',98,'taxiThin')]:
    copy('Marker'+key,root/'labels-final-png/DefineSprite_41_GalaxyMapLabels_fla.ItemMarker_Graphics_8'/f'{frame}.png','labels',41,frame,label,
         'Original timeline stop frame. BC7 source atlas decoded losslessly to RGBA with Pillow, then rendered by JPEXS; no red missing-bitmap placeholder. These are label rings, not category pin icons.')
for item in json.loads((root/'map-662-frames.json').read_text()):
    label=item['label'];frame=item['frame']
    if label=='none':continue
    source=root/'map-svg/DefineSprite_662_Icons'/f'{frame}.svg'
    svg=ET.parse(source).getroot()
    raster=any(x.tag.endswith('}image') or any('bitmap' in k.lower() for k in x.attrib) for x in svg.iter())
    if raster:source=root/'map-final-png/DefineSprite_662_Icons'/f'{frame}.png'
    key='Map_'+label
    copy(key,source,'map',662,frame,label,'Current map UI Icons timeline; marker legend resolves its DS icon string directly to this frame. Original colours retained.')
    current.append(dict(label=label,key=key,frame=frame,extension=source.suffix,sprite=662))
copy('Map_CurrentLocationMarker',root/'map-svg/DefineSprite_1617_assets.CurrentLocationMarker/1.svg','map',1617,1,'assets.CurrentLocationMarker')
current.append(dict(label='CurrentLocationMarker',key='Map_CurrentLocationMarker',frame=1,extension='.svg',sprite=1617))
manifest=dict(generator='research/Build-GalaxyIconAssets.py',extractor='research/Extract-GalaxyUiResources.py',
              exporter='JPEXS Free Flash Decompiler 26.4.0',gameProcessAccess=False,
              exportBytesUnchanged=True,sources=json.loads((root/'resources.json').read_text()),
              rasterDecode=dict(source='labels.bin',atlas='GalaxyMapLabels_I5.dds',width=2048,height=256,
                  gpuOffset=47519,gpuBytes=524288,gpuSha256=hashlib.sha256((root/'labels.bin').read_bytes()[47519:]).hexdigest(),
                  rgbaSha256=hashlib.sha256(Image.open(root/'labels-atlas.png').convert('RGBA').tobytes()).hexdigest(),
                  note='Same BC7 decoder as Build-GameIconAssets.py. Private labels-render.gfx changes only the external texture filename to the lossless decoded atlas PNG to avoid the JPEXS DDS decoder limitation.'),
              currentMapRasterDecode=json.loads((root/'map-atlas-evidence.json').read_text()),
              currentMapBitmapDependencies={key:dependencies[key] for key in ('allDependenciesResolved','framesWithBitmap','uniqueSubImages','sourceAtlasImageIds')},
              currentMapNotes='Current mapui has Colonisation/Powerplay/Modes classes. Older galaxymapui BookmarkButtonIcon is retained as legacy UI artwork only; it does not prove world marker selection.',
              nativeBookmarkMapping=dict(functionRva='26020A0',decoderRva='261F820',field='row+4C iconName uint',
                  values={'2':'station_bernal','3':'station_coriolis','4':'station_orbis','5':'station_outpost','6':'surface_port',
                          '7':'surface_settlement','8':'planet_landable','9':'planet','10':'star','11':'asteroid','12':'system',
                          '13':'megaShip_dockable','14':'megaShip_undockable','17':'station_dodec'},default='default',
                  unavailableFrame='station_dodec has no frame in this original BookmarkButtonIcon timeline; explicit default fallback'),icons=icons)
(out/'source.json').write_text(json.dumps(manifest,ensure_ascii=False,indent=2)+'\n',encoding='utf-8')
# Generate a closed, ordinal name catalogue from the actual timeline labels.
entries=[]
for item in current:
    entries.append('        ["'+item['label']+'"] = new("'+item['label']+'","Assets/GalaxyIcons/'+item['key']+item['extension']+'",'+str(item['sprite'])+','+str(item['frame'])+'),')
code=('// Generated by research/Build-GalaxyIconAssets.py from original mapui timeline labels.\n'
      'using System.Collections.Frozen;\n\nnamespace XFEEDToolBox.Core.Galaxy;\n\n'
      'public static partial class GalaxyOriginalIcons\n{\n'
      '    /// <summary>Current original map UI icon names; colours and geometry are retained.</summary>\n'
      '    public static IReadOnlyDictionary<string,GalaxyOriginalIcon> MapFrames { get; } =\n'
      '        new Dictionary<string,GalaxyOriginalIcon>(StringComparer.Ordinal)\n    {\n'+ '\n'.join(entries)+
      '\n    }.ToFrozenDictionary(StringComparer.Ordinal);\n\n'
      '    /// <summary>Returns null for names absent from the original movie. No semantic guessing.</summary>\n'
      '    public static GalaxyOriginalIcon? Map(string frameName)=>MapFrames.GetValueOrDefault(frameName);\n}\n')
Path('XFEEDToolBox.Core/Galaxy/GalaxyOriginalIcons.Map.cs').write_text(code,encoding='utf-8')
print(json.dumps(dict(imported=len(icons),output=str(out),sourceFramesUnchanged=True)))
