# Requires Python, pyswisseph, scipy. Swiss Ephemeris AGPL or commercial licensing applies.
import json,gzip,datetime as dt
from pathlib import Path
import swisseph as s
from scipy.optimize import brentq
O=Path(__file__).resolve().parent;bodies=['Sun','Moon','Mercury','Venus','Mars','Jupiter','Saturn','Uranus'];codes=[s.SUN,s.MOON,s.MERCURY,s.VENUS,s.MARS,s.JUPITER,s.SATURN,s.URANUS];eras={}
def angle(j):return s.calc_ut(j,s.URANUS,s.FLG_MOSEPH|s.FLG_SPEED)[0][0]
def iso(j):
 y,m,d,h=s.revjul(j);return (dt.datetime(y,m,d,tzinfo=dt.timezone.utc)+dt.timedelta(hours=h)).isoformat(timespec='seconds').replace('+00:00','Z')
ingresses=[]
for name,begin,end in [('historical',dt.date(1939,1,1),dt.date(1951,1,1)),('forward',dt.date(2024,1,1),dt.date(2035,1,1))]:
 rows=[]
 for n in range((end-begin).days+1):
  d=begin+dt.timedelta(days=n);j=s.julday(d.year,d.month,d.day,12);row=[]
  for code in codes:
   p,f=s.calc_ut(j,code,s.FLG_MOSEPH|s.FLG_SPEED);assert f&s.FLG_MOSEPH;row.extend(round(v,8) for v in [p[0],p[1],p[3]])
  rows.append(row)
 eras[name]={'start':str(begin)+'T12:00:00Z','end':str(end)+'T12:00:00Z','rows':rows}
 start=s.julday(begin.year,begin.month,begin.day,12)
 for i,(a,b) in enumerate(zip(rows,rows[1:])):
  for target in [30,60,90,120]:
   x=(a[21]-target+180)%360-180;y=(b[21]-target+180)%360-180
   if x*y<0 and abs(y-x)<180:
    root=brentq(lambda j:(angle(j)-target+180)%360-180,start+i,start+i+1,xtol=1e-9);p,f=s.calc_ut(root,s.URANUS,s.FLG_MOSEPH|s.FLG_SPEED)
    ingresses.append({'era':name,'utc':iso(root),'boundary':target,'direction':'Direct' if p[3]>0 else 'Retrograde','enteredSign':int(target/30) if p[3]>0 else int(target/30)-1})
points=[('1941-03-11','Lend-Lease Act','Material aid and an expanding role before formal U.S. entry into the war.','https://www.archives.gov/milestone-documents/lend-lease-act'),('1941-08-14','Atlantic Charter issued','A U.S.–British statement of war aims and principles; not a binding treaty.','https://www.fdrlibrary.org/atlantic-charter'),('1944-07-22','Bretton Woods conference closes','A new international monetary framework was developed through a multilateral conference.','https://www.federalreservehistory.org/essays/bretton-woods-created'),('1945-09-02','Japan’s surrender instrument signed','A milestone of Allied victory and the transition to the postwar order, after enormous human loss.','https://www.archives.gov/milestone-documents/surrender-of-japan'),('1945-10-24','UN Charter enters into force','A new multilateral institution, with the United States among its founders.','https://www.un.org/en/about-us/un-charter/'),('1947-03-12','Truman Doctrine speech','A commitment to assist Greece and Turkey became a major Cold War policy statement.','https://www.archives.gov/milestone-documents/truman-doctrine'),('1947-07-26','National Security Act signed','New national-security institutions, including the NSC and CIA, formed part of a governmental reorganization.','https://nsarchive.gwu.edu/document/28653-document-9-national-security-act-1947-26-july-1947'),('1948-04-03','Marshall Plan legislation signed','U.S. aid to European reconstruction strengthened economic and political links.','https://www.archives.gov/milestone-documents/marshall-plan'),('1948-06-26','U.S. Berlin Airlift begins','The airlift supplied West Berlin after the Soviet blockade; British operations followed.','https://history.state.gov/milestones/1945-1952/berlin-airlift')]
points.extend([('1941-12-07','Attack on Pearl Harbor','Japanese forces attacked U.S. military facilities in Hawaii, with devastating loss of life.','https://www.archives.gov/legislative/features/pearl-harbor'),('1941-12-08','U.S. declares war on Japan','Congress declared war following Roosevelt’s address, the day after Pearl Harbor.','https://www.archives.gov/milestone-documents/joint-address-to-congress-declaration-of-war-against-japan')]);points.sort(key=lambda x:x[0])
result={'meta':{'bodies':bodies,'columns':'Each body: apparent geocentric tropical longitude, latitude, longitude speed, in degrees and degrees/day.','sample':'Daily 12:00 UT; linear interpolation between dates. Historical milestones use 12:00 UT, not asserted event hours.','ephemeris':'Swiss Ephemeris 2.10.03, explicit Moshier analytical mode; UT and built-in Delta T.','mapping':'Uranus → Keter is the user’s Babylon model. Uranus was not one of the seven classical planetary rulers.','rollForward':'Find every crossing of the selected historical Uranus longitude in the 2025–2033 comparison period. Daily-bracket linear interpolation gives approximate dates. Repeated retrograde crossings are retained; other planets are calculated independently.'},'eras':eras,'ingresses':ingresses,'milestones':[dict(zip(['date','title','text','source'],p)) for p in points]}
with gzip.open(O/'uranus.json.gz','wt') as f:json.dump(result,f,separators=(',',':'))
print('Uranus layer:',sum(len(e['rows']) for e in eras.values()),'eight-body daily samples;',len(ingresses),'refined boundary crossings.')
