import os
import math
from datetime import datetime, timedelta
from zoneinfo import ZoneInfo

import swisseph as swe
from kerykeion import AstrologicalSubject, KerykeionChartSVG


# =========================
# SETTINGS
# =========================

CHARTS_DIR = "charts"
os.makedirs(CHARTS_DIR, exist_ok=True)

# If you have ephemeris files, set path here
# Example: /usr/share/ephe or backend/ephe
EPHE_PATH = "/usr/share/ephe"
if os.path.exists(EPHE_PATH):
    swe.set_ephe_path(EPHE_PATH)

SIGNS = [
    "Aries", "Taurus", "Gemini", "Cancer",
    "Leo", "Virgo", "Libra", "Scorpio",
    "Sagittarius", "Capricorn", "Aquarius", "Pisces"
]


def normalize_deg(x):
    return x % 360


def angle_diff(a, b):
    d = abs((a - b) % 360)
    return min(d, 360 - d)


def longitude_to_sign_degree(lon):
    lon = normalize_deg(lon)
    sign_index = int(lon // 30)
    deg_float = lon % 30
    deg = int(deg_float)
    minute = int(round((deg_float - deg) * 60))

    if minute == 60:
        minute = 0
        deg += 1

    return {
        "sign": SIGNS[sign_index],
        "degree": f"{deg}° {minute:02d}'",
        "longitude": round(lon, 6)
    }


def local_to_jd_utc(year, month, day, hour, minute, timezone_name):
    tz = ZoneInfo(timezone_name)
    local_dt = datetime(year, month, day, hour, minute, 0, tzinfo=tz)
    utc_dt = local_dt.astimezone(ZoneInfo("UTC"))

    jd = swe.julday(
        utc_dt.year,
        utc_dt.month,
        utc_dt.day,
        utc_dt.hour + utc_dt.minute / 60 + utc_dt.second / 3600
    )

    return jd, local_dt, utc_dt


def sun_longitude_from_jd(jd):
    result, flags = swe.calc_ut(jd, swe.SUN)
    return normalize_deg(result[0])


def find_solar_return_datetime(
    natal_sun_lon,
    return_year,
    timezone_name,
    start_month,
    start_day
):
    """
    Find exact time when transiting Sun returns to natal Sun longitude.
    Search around birthday: -3 days to +3 days.
    """

    tz = ZoneInfo(timezone_name)

    start_local = datetime(
        return_year,
        start_month,
        start_day,
        0,
        0,
        0,
        tzinfo=tz
    ) - timedelta(days=3)

    end_local = start_local + timedelta(days=7)

    best_dt = None
    best_diff = 999

    # First rough search every 1 hour
    current = start_local
    while current <= end_local:
        utc_dt = current.astimezone(ZoneInfo("UTC"))
        jd = swe.julday(
            utc_dt.year,
            utc_dt.month,
            utc_dt.day,
            utc_dt.hour + utc_dt.minute / 60 + utc_dt.second / 3600
        )

        sun_lon = sun_longitude_from_jd(jd)
        diff = angle_diff(sun_lon, natal_sun_lon)

        if diff < best_diff:
            best_diff = diff
            best_dt = current

        current += timedelta(hours=1)

    # Refine around best hour every 1 minute
    refine_start = best_dt - timedelta(hours=2)
    refine_end = best_dt + timedelta(hours=2)

    best_dt_2 = best_dt
    best_diff_2 = best_diff

    current = refine_start
    while current <= refine_end:
        utc_dt = current.astimezone(ZoneInfo("UTC"))
        jd = swe.julday(
            utc_dt.year,
            utc_dt.month,
            utc_dt.day,
            utc_dt.hour + utc_dt.minute / 60 + utc_dt.second / 3600
        )

        sun_lon = sun_longitude_from_jd(jd)
        diff = angle_diff(sun_lon, natal_sun_lon)

        if diff < best_diff_2:
            best_diff_2 = diff
            best_dt_2 = current

        current += timedelta(minutes=1)

    return best_dt_2, best_diff_2


# =========================
# USER BIRTH DATA
# =========================

birth_data = {
    "name": "User",
    "year": 2003,
    "month": 11,
    "day": 18,
    "hour": 12,
    "minute": 0,
    "city": "Morbi",
    "nation": "IN",
    "lat": 22.8173,
    "lng": 70.8377,
    "tz_str": "Asia/Kolkata",
}

# Solar Return year and return location
return_year = 2026

return_location = {
    "city": "Ahmedabad",
    "nation": "IN",
    "lat": 23.0225,
    "lng": 72.5714,
    "tz_str": "Asia/Kolkata",
}


# =========================
# STEP 1: Natal Sun
# =========================

birth_jd, birth_local, birth_utc = local_to_jd_utc(
    birth_data["year"],
    birth_data["month"],
    birth_data["day"],
    birth_data["hour"],
    birth_data["minute"],
    birth_data["tz_str"]
)

natal_sun_lon = sun_longitude_from_jd(birth_jd)
natal_sun_info = longitude_to_sign_degree(natal_sun_lon)

print("\n==============================")
print("NATAL SUN")
print("==============================")
print("Birth Local:", birth_local)
print("Birth UTC:", birth_utc)
print("Natal Sun:", natal_sun_info)


# =========================
# STEP 2: Find Solar Return Time
# =========================

solar_return_dt, diff = find_solar_return_datetime(
    natal_sun_lon=natal_sun_lon,
    return_year=return_year,
    timezone_name=return_location["tz_str"],
    start_month=birth_data["month"],
    start_day=birth_data["day"]
)

print("\n==============================")
print("SOLAR RETURN TIME")
print("==============================")
print("Solar Return Local:", solar_return_dt)
print("Difference from natal Sun:", diff, "degree")


# =========================
# STEP 3: Create Kerykeion Subjects
# =========================

natal_subject = AstrologicalSubject(
    name=birth_data["name"],
    year=birth_data["year"],
    month=birth_data["month"],
    day=birth_data["day"],
    hour=birth_data["hour"],
    minute=birth_data["minute"],
    city=birth_data["city"],
    nation=birth_data["nation"],
    lat=birth_data["lat"],
    lng=birth_data["lng"],
    tz_str=birth_data["tz_str"],
)

solar_subject = AstrologicalSubject(
    name=f"Solar_Return_{return_year}",
    year=solar_return_dt.year,
    month=solar_return_dt.month,
    day=solar_return_dt.day,
    hour=solar_return_dt.hour,
    minute=solar_return_dt.minute,
    city=return_location["city"],
    nation=return_location["nation"],
    lat=return_location["lat"],
    lng=return_location["lng"],
    tz_str=return_location["tz_str"],
)

print("\n==============================")
print("KERYKEION SUBJECTS CREATED")
print("==============================")
print("Natal subject OK")
print("Solar Return subject OK")


# =========================
# STEP 4: Generate Solar Return Chart
# =========================

print("\n==============================")
print("GENERATING CHART")
print("==============================")

try:
    # Dual wheel style: Natal + Solar Return as Transit chart
    chart = KerykeionChartSVG(
        natal_subject,
        chart_type="Transit",
        second_obj=solar_subject,
        new_output_directory=CHARTS_DIR
    )

    chart.makeSVG()

    print("✅ Solar Return chart generated successfully")
    print("Check SVG files here:")
    print(os.path.abspath(CHARTS_DIR))

except TypeError as e:
    print("Transit chart_type failed, trying without new_output_directory...")
    print("Error:", e)

    chart = KerykeionChartSVG(
        natal_subject,
        chart_type="Transit",
        second_obj=solar_subject
    )
    chart.makeSVG()

    print("✅ Solar Return chart generated successfully")
    print("Check current folder for SVG")


print("\nGenerated SVG files:")
for file in os.listdir(CHARTS_DIR):
    if file.endswith(".svg"):
        print("-", os.path.join(CHARTS_DIR, file))
