"""Build an offline companion catalogue from attributed public reference data. Never touches game files."""
import csv, datetime, hashlib, json, pathlib, re, urllib.request
root = pathlib.Path(__file__).resolve().parents[1]
ref = root / 'artifacts/engineering-reference'
out = root / 'XFEEDToolBox.Core/Engineering'
out.mkdir(parents=True, exist_ok=True)
def read(name): return json.loads((ref / name).read_text(encoding='utf-8-sig'))
def norm(s): return ''.join(c.lower() for c in s if c.isalnum())
blueprints, entries = read('blueprints.json'), read('entryData.json')
fd, specials = read('coriolis-blueprints.json'), read('coriolis-specials.json')
ids = {}
for key, value in fd.items():
    for grade, recipe in value.get('grades', {}).items():
        if recipe.get('uuid'): ids[recipe['uuid']] = key
for key, value in specials.items():
    if value.get('uuid'): ids[value['uuid']] = key
materials = {e['Name']: e for e in entries}
captured=read('captured-rules.json')
captured_specials={r['special']:r for r in captured.get('recipes',[]) if r.get('special')}
fdev = list(csv.DictReader((ref/'fdev-material.csv').read_text(encoding='utf-8-sig').splitlines()))
symbols = {norm(e['name']):e['symbol'].lower() for e in fdev}
recipes = []
types = {r['Type'] for r in blueprints if r.get('Grade') in [1,2,3,4,5] and any(not e.startswith('@') for e in r.get('Engineers',[])) and r['Type'] not in ['Suit','Weapon','Unlock']}
for r in blueprints:
    if r['Type'] not in types or not r.get('Engineers') or any(e.startswith('@') for e in r['Engineers']): continue
    grade = r.get('Grade', 0)
    if grade not in [0,1,2,3,4,5]: continue
    # Grade-less module recipes here are experimental effects, not technology unlocks.
    recipes.append(dict(type=r['Type'], name=r['Name'], grade=grade, journalName=ids.get(r.get('CoriolisGuid'), ''),
        engineers=r['Engineers'], ingredients=[dict(key=symbols.get(norm(i['Name']),materials.get(i['Name'],{}).get('FormattedName',norm(i['Name']))), name=i['Name'], count=i['Size']) for i in r['Ingredients']],
        effects=[e['Property']+': '+e['Effect'] for e in r.get('Effects',[])]))
    recipe=recipes[-1]
    if grade==0 and recipe['journalName'] in captured_specials:
        recipe['ingredients']=[dict(key=i['name'],name=next((e['name'] for e in fdev if e['symbol'].lower()==i['name']),i['name']),count=i['qty']) for i in captured_specials[recipe['journalName']]['ingredients']]
rarity={'VeryCommon':1,'Common':2,'Standard':3,'Rare':4,'VeryRare':5}
mats=[dict(key=e['symbol'].lower(),name=e['name'],grade=int(e['rarity']) if e['rarity'].isdigit() else 0,category=e['type'],group=e['category']) for e in fdev]
engineers=list(csv.DictReader((ref/'fdev-engineers.csv').read_text(encoding='utf-8-sig').splitlines()))
catalog=dict(builtAt=datetime.datetime.now(datetime.timezone.utc).isoformat(),sources=['https://github.com/msarilar/EDEngineer','https://github.com/EDCD/coriolis-data','https://github.com/EDCD/FDevIDs'],recipes=recipes,materials=mats,engineerMarkets={e['id']:int(e['market_id']) for e in engineers if e['market_id'].isdigit()})
(out/'catalog.json').write_text(json.dumps(catalog,ensure_ascii=False,separators=(',',':')),encoding='utf-8')
(out/'rules.json').write_text(json.dumps(dict(source='Elite-Dangerous-all-captures.zip: online-solo-capture-20261020/cold-start/process/decoded/http-response-000179.json',captureSha256='b94ab4ebab9cc81a812817b0f528fcff17d4dae21e89585233c6d0e7065c1338',progressPercent=captured['progressPercent'],reputationThresholds=captured['reputationThresholds'],reputationRewards=captured['reputationRewards']),indent=2),encoding='utf-8')
notice=out/'Data-Notice.txt'
notice.write_text('Material names and recipe data: EDEngineer, copyright (c) 2016 Max, MIT license below. Journal blueprint identifiers are cross-referenced with EDCD/coriolis-data. Coriolis data is copyright Frontier Developments plc and subject to https://www.frontierstore.net/terms-and-conditions/.\n\n'+(ref/'LICENSE').read_text(encoding='utf-8-sig')+'\n\nCoriolis notice:\n'+(ref/'coriolis-LICENSE.md').read_text(encoding='utf-8-sig'),encoding='utf-8')
manifest={n:hashlib.sha256((ref/n).read_bytes()).hexdigest() for n in ['blueprints.json','entryData.json','coriolis-blueprints.json','coriolis-specials.json','fdev-material.csv','fdev-engineers.csv','LICENSE','coriolis-LICENSE.md']}
(out/'sources.json').write_text(json.dumps(dict(sources=catalog['sources'],downloadedAt=catalog['builtAt'],sha256=manifest),indent=2),encoding='utf-8')
print(json.dumps(dict(recipes=len(recipes),types=len(types),materials=len(mats),journalMappings=sum(bool(r['journalName']) for r in recipes)),indent=2))
