#!/usr/bin/env /home/dn2ane/sun_venv/bin/python3
import datetime
import math
import subprocess
import pandas as pd
import pvlib

# Standortkonfiguration (Muenchen)
LATITUDE = 48.173333
LONGITUDE = 11.635
ALTITUDE = 520 # 520 Meter

def get_astronomical_eot_and_sun_transit(date_obj, longitude_deg=LONGITUDE):
    mesz_start = datetime.date(2026, 3, 29)
    mesz_end = datetime.date(2026, 10, 25)
    
    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

# Aktuelle Sonnenposition berechnen
now = pd.Timestamp.now(tz="Europe/Berlin")
solpos = pvlib.solarposition.get_solarposition(
    time=now,
    latitude=LATITUDE,
    longitude=LONGITUDE,
    altitude=ALTITUDE,
    method="nrel_numpy",
)

elevation = solpos["apparent_elevation"].iloc[0]
azimuth = solpos["azimuth"].iloc[0]

alt_rad = math.radians(elevation)
az_rad = math.radians(azimuth)

sun_x = math.cos(alt_rad) * math.sin(az_rad)
sun_y = math.sin(alt_rad)
sun_z = math.cos(alt_rad) * math.cos(az_rad)

len_tan_elev = 1 / math.tan(alt_rad)

sun_brightness = max(0.0, min(1.0, math.sin(alt_rad) * 2))
sky_brightness = max(0.05, min(1.0, (math.sin(alt_rad) + 0.2) * 1.2))

# Zeitzone bestimmen
tz_name = "MESZ" if now.dst() != pd.Timedelta(0) else "MEZ"

eot, is_dst, total_offset = get_astronomical_eot_and_sun_transit(now.date())

# Deutsche Wochentage Mappen
weekdays_de = {
    "Monday": "Montag",
    "Tuesday": "Dienstag",
    "Wednesday": "Mittwoch",
    "Thursday": "Donnerstag",
    "Friday": "Freitag",
    "Saturday": "Samstag",
    "Sunday": "Sonntag",
}
weekday_str = weekdays_de[now.strftime("%A")]
date_str = f"{weekday_str}, {now.strftime('%d.%m.%Y')}"
time_str = now.strftime(f"%H:%M:%S {tz_name}")

sun_info_str = f"Azimut: {azimuth:.1f} Grad Elev: {elevation:.1f} Grad"
pos_info_str = f"Muenchen ({LATITUDE:.4f} N, {LONGITUDE:.4f} E)"
offset_info_str = f"total_offset = {total_offset:.1f} min"
zgl_info_str = f"zgl = {eot:.1f} min"

# Beleuchtung (Sonne)
if sun_y > -0.05:
    light_code = f"""
    light_source {{
        <{sun_x:.6f}, {sun_y:.6f}, {sun_z:.6f}> * 1000
        color rgb <1.5, 1.42, 1.28> * {sun_brightness:.2f}
        area_light <10, 0, 0>, <0, 0, 10>, 9, 9
        adaptive 1
        jitter
    }}
    """
else:
    light_code = """
    light_source {
        <0, 1000, -500>
        color rgb <0.02, 0.02, 0.05>
    }
    """
    
dial_elements = []
for hour in range(6, 21):
    angle_deg = (hour - 12 - total_offset / 60) * 15 
    x_offset = -0.18 if hour >= 10 else -0.09
    
    dial_elements.append(f"""
    cylinder {{
        <0, 0.001, 0>, <0, 0.001, 3.0>, 0.015
        pigment {{ DarkPigment }}
        finish {{ DarkFinish }}
        rotate <0, {angle_deg}, 0>
    }}
    text {{
        ttf FontFile
        "{hour}"
        0.02, 0
        pigment {{ DarkPigment }}
        finish {{ DarkFinish }}
        scale <0.45, 0.45, 0.45>
        rotate <90, 0, 0>
        translate <{x_offset}, 0.01, 3.20>
        rotate <0, {angle_deg}, 0>
    }}
    """)

# Himmelsrichtungen N, E, S, W
compass_labels = [
    ("N", 0, "<-0.10, 0.01, 3.60>"),
    ("E", 90, "<-0.10, 0.01, 3.60>"),
    ("S", 180, "<-0.10, 0.01, 3.60>"),
    ("W", -90, "<-0.12, 0.01, 3.60>"),
]

for label, angle, pos in compass_labels:
    dial_elements.append(f"""
    text {{
        ttf FontFile
        "{label}"
        0.03, 0
        pigment {{ RedPigment }}
        finish {{ DarkFinish }}
        scale <0.55, 0.55, 0.55>
        rotate <90, 0, 0>
        translate {pos}
        rotate <0, {angle}, 0>
    }}
    """)

dial_code = "\n".join(dial_elements)

pov_content = f"""#version 3.7;
#include "screen.inc"

global_settings {{
    assumed_gamma 1.0
    radiosity {{ 
        count 100 
        error_bound 0.5 
    }}
}}

Set_Camera(<0, 9, -11>, <0, 0, 0.2>, 44)

{light_code}

sky_sphere {{
    pigment {{
        gradient y
        color_map {{
            [0.0 color rgb <0.6, 0.7, 0.9> * {sky_brightness:.2f}] 
            [1.0 color rgb <0.2, 0.4, 0.8> * {sky_brightness:.2f}] 
        }}
    }}
}}

plane {{
    y, 0
    texture {{
        pigment {{ color rgb <0.85, 0.82, 0.75> }}
        finish {{ ambient 0.1 diffuse 0.8 roughness 0.3 }}
    }}
}}

cylinder {{
    <0, 0, 0>, <0, 2, 0>, 0.05
    texture {{
        pigment {{ color rgb <0.3, 0.3, 0.3> }}
        finish {{ metallic brilliance 2.0 reflection 0.5 roughness 0.05 }}
    }}
}}

#declare DarkFinish = finish {{ ambient 0.1 diffuse 0.6 }};
#declare DarkPigment = pigment {{ color rgb <0.15, 0.15, 0.15> }};
#declare RedPigment = pigment {{ color rgb <0.8, 0.1, 0.1> }};
#declare TextPigment = pigment {{ color rgb <0.1, 0.2, 0.4> }};
#declare FontFile = "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf";

torus {{
    3.0, 0.02
    pigment {{ DarkPigment }}
    finish {{ DarkFinish }}
    translate <0, 0.001, 0>
}}

{dial_code}

#declare Aspect = image_width / image_height;

#declare InfoText0 = text {{
    ttf FontFile
    "{date_str}"
    0.01, 0
    pigment {{ TextPigment }}
    finish {{ ambient 1.0 diffuse 0.0 }}
    scale <0.032, 0.032, 0.032>
}};

#declare InfoText1 = text {{
    ttf FontFile
    "{time_str}"
    0.01, 0
    pigment {{ TextPigment }}
    finish {{ ambient 1.0 diffuse 0.0 }}
    scale <0.038, 0.038, 0.038>
}};

#declare InfoText2 = text {{
    ttf FontFile
    "{sun_info_str}"
    0.01, 0
    pigment {{ TextPigment }}
    finish {{ ambient 1.0 diffuse 0.0 }}
    scale <0.028, 0.028, 0.028>
}};

#declare InfoText3 = text {{
    ttf FontFile
    "{pos_info_str}"
    0.01, 0
    pigment {{ TextPigment }}
    finish {{ ambient 1.0 diffuse 0.0 }}
    scale <0.028, 0.028, 0.028>
}};

#declare InfoText4 = text {{
    ttf FontFile
    "{offset_info_str}"
    0.01, 0
    pigment {{ TextPigment }}
    finish {{ ambient 1.0 diffuse 0.0 }}
    scale <0.028, 0.028, 0.028>
}};

#declare InfoText5 = text {{
    ttf FontFile
    "{zgl_info_str}"
    0.01, 0
    pigment {{ TextPigment }}
    finish {{ ambient 1.0 diffuse 0.0 }}
    scale <0.028, 0.028, 0.028>
}};

Screen_Object(InfoText0, <0.03, 0.95>, <0, 0>, Aspect, 1.0)
Screen_Object(InfoText1, <0.03, 0.90>, <0, 0>, Aspect, 1.0)
Screen_Object(InfoText2, <0.03, 0.85>, <0, 0>, Aspect, 1.0)
Screen_Object(InfoText3, <0.03, 0.80>, <0, 0>, Aspect, 1.0)
Screen_Object(InfoText4, <0.04, 0.75>, <0, 0>, Aspect, 1.0)
Screen_Object(InfoText5, <0.04, 0.70>, <0, 0>, Aspect, 1.0)
"""

with open("render.pov", "w") as f:
    f.write(pov_content)

output_file = "/var/www/html/pov/sonnenuhr_current.png"
subprocess.run(
    [
        "povray",
        "+Irender.pov",
        f"+O{output_file}",
        "+W1024",
        "+H576",
        "+A0.1",
        "-D",
    ],
    check=True,
)
