#! /usr/bin/python3
import datetime
import math

def get_astronomical_eot_and_sun_transit(date_obj, longitude_deg=11.635):
    mesz_start = datetime.date(2027, 3, 28)
    mesz_end = datetime.date(2027, 10, 31)
    
    is_dst = mesz_start <= date_obj < mesz_end
    tz_offset_hours = 2.0 if is_dst else 1.0
    
    year = date_obj.year
    month = date_obj.month
    day = date_obj.day
    
    if month <= 2:
        year_adj = year - 1
        month_adj = month + 12
    else:
        year_adj = year
        month_adj = month
        
    A = math.floor(year_adj / 100)
    B = 2 - A + math.floor(A / 4)
    jd = math.floor(365.25 * (year_adj + 4716)) + math.floor(30.6001 * (month_adj + 1)) + day + B - 1524.5 + 0.5
    
    # Julianische Jahrhunderte seit J2000.0 (T)
    T = (jd - 2451545.0) / 36525.0
    
    # Mittlere Ekliptik-Laenge der Sonne (L0) in Grad
    L0 = (280.46646 + T * (36000.76983 + T * 0.0003032)) % 360.0
    
    # Mittlere Anomalie der Sonne (M) in Grad
    M = (357.52911 + T * (35999.05029 - 0.0001537 * T)) % 360.0
    
    # Exzentrizitaet der Erdbahn (e)
    e = 0.016708634 - T * (0.000042037 + 0.0000001267 * T)
    
    # Mittelpunktsgleichung (C) in Grad
    M_rad = math.radians(M)
    C = (1.914602 - T * (0.004817 + 0.000014 * T)) * math.sin(M_rad) \
        + (0.019993 - 0.000101 * T) * math.sin(2 * M_rad) \
        + 0.000289 * math.sin(3 * M_rad)
        
    # Schiefe der Ekliptik (eps0)
    eps0 = 23.0 + (26.0 + (21.448 - T * (46.8150 + T * (0.00059 - T * 0.001813))) / 60.0) / 60.0
    eps_rad = math.radians(eps0)
    y = math.tan(eps_rad / 2.0) ** 2
    
    L0_rad = math.radians(L0)
    
    # Zeitgleichung (Equation of Time, EoT) in Minuten
    eot_minutes = 4.0 * math.degrees(
        y * math.sin(2.0 * L0_rad)
        - 2.0 * e * math.sin(M_rad)
        + 4.0 * e * y * math.sin(M_rad) * math.cos(2.0 * L0_rad)
        - 0.5 * y * y * math.sin(4.0 * L0_rad)
        - 1.25 * e * e * math.sin(2.0 * M_rad)
    )
    
    tz_meridian = tz_offset_hours * 15.0  
    location_offset_minutes = (tz_meridian - longitude_deg) * 4.0  
    
    total_offset_minutes = location_offset_minutes - eot_minutes
    
    return eot_minutes, is_dst, total_offset_minutes

def format_minutes_ms(minutes_val):
    sign = "+" if minutes_val >= 0 else "-"
    abs_val = abs(minutes_val)
    mins = int(abs_val)
    secs = (abs_val - mins) * 60.0
    whole_secs = int(secs)
    ms = round((secs - whole_secs) * 1000)
    
    if ms >= 1000:
        ms -= 1000
        whole_secs += 1
    if whole_secs >= 60:
        whole_secs -= 60
        mins += 1
        
    return f"{sign}{mins:02d}:{whole_secs:02d}.{ms:03d} min"

def format_time_ms(base_hour, offset_minutes):
    total_seconds = base_hour * 3600 + offset_minutes * 60
    hours = int(total_seconds // 3600)
    rem_seconds = total_seconds % 3600
    minutes = int(rem_seconds // 60)
    seconds = rem_seconds % 60
    whole_secs = int(seconds)
    ms = round((seconds - whole_secs) * 1000)
    
    if ms >= 1000:
        ms -= 1000
        whole_secs += 1
    if whole_secs >= 60:
        whole_secs -= 60
        minutes += 1
    if minutes >= 24:
        hours %= 24
        
    return f"{hours:02d}:{minutes:02d}:{whole_secs:02d}.{ms:03d}"

def generate_table_2027(output_filename="umrechnungstabelle_sonnenuhr_2027.txt"):
    longitude = 11.635
    
    header = [
        "=" * 80,
        "UMRECHNUNGSTABELLE: SONNENUHR (WOZ) -> UHRZEIT (MEZ/MESZ) FUER DAS JAHR 2027",
        f"Standort-Laenge: {longitude:.6f} Grad Ost",
        "=" * 80,
        f"{'Datum':<14} | {'ZGL-Wert':<16} | {'Gesamt-Offset':<18} | {'Sonnenuhr 12:00 WOZ ist'}",
        "-" * 80
    ]
    
    lines = list(header)
    start_date = datetime.date(2027, 1, 1)
    end_date = datetime.date(2027, 12, 31)
    current_date = start_date

    months_de = ["", "Januar", "Februar", "Maerz", "April", "Mai", "Juni",
                 "Juli", "August", "September", "Oktober", "November", "Dezember"]

    while current_date <= end_date:
        eot, is_dst, total_offset = get_astronomical_eot_and_sun_transit(current_date, longitude)
        
        date_str = f"{current_date.day:02d}. {months_de[current_date.month]}"
        zgl_str = format_minutes_ms(eot)
        offset_str = format_minutes_ms(total_offset)
        transit_str = f"{format_time_ms(12, total_offset)} {'MESZ' if is_dst else 'MEZ'}"
        
        lines.append(f"{date_str:<14} | {zgl_str:<16} | {offset_str:<18} | {transit_str}")
        current_date += datetime.timedelta(days=1)
        
    lines.append("-" * 80)
    
    with open(output_filename, "w", encoding="utf-8") as f:
        f.write("\n".join(lines))

if __name__ == "__main__":
    generate_table_2027()
