import os
# -*- coding: utf-8 -*-
"""
radix_engine.py - Grundhoroskop (Radix) via Swiss Ephemeris
Baustein 2 der fine-senses Astro-Pipeline.

Liefert:
  - Aszendent (AC) und Medium Coeli (MC)
  - 12 Haeuserspitzen (Placidus 'P' oder Koch 'K')
  - Planeten Sonne..Pluto, Chiron, Mondknoten mit Zeichen, Grad und Haus

Zeitzonen-Logik:
  Die Umrechnung lokale Zeit -> UT erfolgt ueber die IANA-Zeitzonendatenbank
  (zoneinfo). Diese kennt historisch korrekt, dass Deutschland 1950-1979 KEINE
  Sommerzeit hatte (erst ab 1980 wieder eingefuehrt) sowie alle exakten
  DST-Wechseldaten. Fuer auslaendische Geburten genuegt der passende tz-Name.
"""
import swisseph as swe
swe.set_ephe_path(os.path.join(os.path.dirname(os.path.abspath(__file__)), "ephe"))
from datetime import datetime
from zoneinfo import ZoneInfo

ZEICHEN = ['Widder', 'Stier', 'Zwillinge', 'Krebs', 'Löwe', 'Jungfrau',
           'Waage', 'Skorpion', 'Schütze', 'Steinbock', 'Wassermann', 'Fische']

PLANETEN = [
    ('Sonne',      swe.SUN),
    ('Mond',       swe.MOON),
    ('Merkur',     swe.MERCURY),
    ('Venus',      swe.VENUS),
    ('Mars',       swe.MARS),
    ('Jupiter',    swe.JUPITER),
    ('Saturn',     swe.SATURN),
    ('Uranus',     swe.URANUS),
    ('Neptun',     swe.NEPTUNE),
    ('Pluto',      swe.PLUTO),
    ('Chiron',     swe.CHIRON),
    ('Mondknoten', swe.MEAN_NODE),
]


def _dms(laenge):
    """ekliptische Laenge -> (Zeichen, Grad, Minute) im Zeichen"""
    g = laenge % 30.0
    grad = int(g)
    minute = int(round((g - grad) * 60))
    if minute == 60:
        minute = 0
        grad += 1
    zeichen = ZEICHEN[int(laenge // 30) % 12]
    return zeichen, grad, minute


def _haus(laenge, cusps):
    """Hausnummer 1..12 fuer eine Laenge anhand der 12 Haeuserspitzen (cusps[0]=Haus 1)"""
    for i in range(12):
        a = cusps[i]
        b = cusps[(i + 1) % 12]
        if a <= b:
            if a <= laenge < b:
                return i + 1
        else:  # Haus ueberschreitet 0 Grad Widder
            if laenge >= a or laenge < b:
                return i + 1
    return 12


def local_to_ut(year, month, day, hour, minute, tz='Europe/Berlin'):
    """lokale Zeit -> (UT-Jahr, -Monat, -Tag, UT-Dezimalstunde, Offset-Stunden)"""
    dt_local = datetime(year, month, day, hour, minute, tzinfo=ZoneInfo(tz))
    offset = dt_local.utcoffset().total_seconds() / 3600.0
    dt_utc = dt_local.astimezone(ZoneInfo('UTC'))
    ut = dt_utc.hour + dt_utc.minute / 60.0 + dt_utc.second / 3600.0
    return dt_utc.year, dt_utc.month, dt_utc.day, ut, offset


def compute_radix(year, month, day, hour, minute, lat, lon,
                  tz='Europe/Berlin', hsys=b'P', name=''):
    uy, um, ud, ut, offset = local_to_ut(year, month, day, hour, minute, tz)
    jd = swe.julday(uy, um, ud, ut)
    flags = swe.FLG_SWIEPH | swe.FLG_SPEED
    cusps, ascmc = swe.houses_ex(jd, lat, lon, hsys, flags)
    ac, mc = ascmc[0], ascmc[1]

    planeten = []
    for pname, pid in PLANETEN:
        pos = swe.calc_ut(jd, pid, flags)[0]
        laenge = pos[0]
        retro = pos[3] < 0
        z, g, m = _dms(laenge)
        planeten.append({
            'name': pname, 'zeichen': z, 'grad': g, 'minute': m,
            'haus': _haus(laenge, cusps), 'retro': retro, 'laenge': laenge,
        })

    haeuser = []
    for i, c in enumerate(cusps):
        z, g, m = _dms(c)
        haeuser.append({'haus': i + 1, 'zeichen': z, 'grad': g, 'minute': m, 'laenge': c})

    return {
        'name': name,
        'ut': (uy, um, ud, ut), 'offset': offset, 'tz': tz,
        'hsys': hsys.decode() if isinstance(hsys, bytes) else str(hsys),
        'lat': lat, 'lon': lon,
        'ac': ac, 'mc': mc, 'haeuser': haeuser, 'planeten': planeten,
    }


def print_radix(chart):
    hs_name = {'P': 'Placidus', 'K': 'Koch'}.get(chart['hsys'], chart['hsys'])
    uy, um, ud, ut = chart['ut']
    uh = int(ut); umin = int(round((ut - uh) * 60))
    off = chart['offset']
    print('=' * 60)
    print(f"GRUNDHOROSKOP: {chart['name']}")
    print('=' * 60)
    print(f"Haeusersystem: {hs_name}   Ort: {chart['lat']}, {chart['lon']}   TZ: {chart['tz']}")
    print(f"UT: {ud:02d}.{um:02d}.{uy} {uh:02d}:{umin:02d}  (Offset lokal = UTC{off:+.0f}h)")
    print('-' * 60)
    z, g, m = _dms(chart['ac'])
    print(f"AC: {g:02d}°{m:02d} {z}")
    z, g, m = _dms(chart['mc'])
    print(f"MC: {g:02d}°{m:02d} {z}")
    print('-' * 60)
    print(f"{'Planet':<11}{'Position':<18}{'Haus':<6}")
    for p in chart['planeten']:
        r = ' R' if p['retro'] else ''
        pos = f"{p['grad']:02d}°{p['minute']:02d} {p['zeichen']}{r}"
        print(f"{p['name']:<11}{pos:<18}H{p['haus']}")
    print('-' * 60)
    print("Haeuserspitzen:")
    for h in chart['haeuser']:
        print(f"  H{h['haus']:<2}: {h['grad']:02d}°{h['minute']:02d} {h['zeichen']}")
    print('=' * 60)


if __name__ == '__main__':
    swe.set_ephe_path(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'ephe'))

    # Dirk: 31.03.1976, 15:00 Hamburg (Koch, wie Referenz-Chart)
    chart = compute_radix(1976, 3, 31, 15, 0, 53.55, 10.0,
                          tz='Europe/Berlin', hsys=b'K', name='Dirk Zessin')
    print_radix(chart)

    # --- Verifikation gegen bekanntes Grundhoroskop ---
    erwartet = {
        'Sonne': ('Widder', 8), 'Mond': ('Widder', 8), 'Merkur': ('Widder', 8),
        'Venus': ('Fische', 7), 'Mars': ('Krebs', 10), 'Jupiter': ('Stier', 9),
        'Saturn': ('Krebs', 11), 'Uranus': ('Skorpion', 3), 'Neptun': ('Schütze', 4),
        'Pluto': ('Waage', 2), 'Chiron': ('Widder', 8),
    }
    print("\n=== VERIFIKATION gegen Referenz (AC Jungfrau, MC Stier) ===")
    z, _, _ = _dms(chart['ac']); ac_ok = (z == 'Jungfrau')
    z, _, _ = _dms(chart['mc']); mc_ok = (z == 'Stier')
    print(f"  AC: {'OK' if ac_ok else 'ABWEICHUNG'}   MC: {'OK' if mc_ok else 'ABWEICHUNG'}")
    allok = ac_ok and mc_ok
    pmap = {p['name']: p for p in chart['planeten']}
    for name, (ez, eh) in erwartet.items():
        p = pmap[name]
        ok = (p['zeichen'] == ez and p['haus'] == eh)
        allok = allok and ok
        print(f"  {name:<8}: erwartet {ez} H{eh:<2} -> {p['zeichen']} H{p['haus']}  [{'OK' if ok else 'ABWEICHUNG'}]")
    print(f"\n  GESAMT: {'ALLE REFERENZWERTE OK' if allok else 'ABWEICHUNG GEFUNDEN'}")
