"""base_rates.py — how often the features named in Part Eight occur anyway.
Companion to engine.py.  Requires pyswisseph.  Run: python base_rates.py
"""
import bisect
import swisseph as swe
swe.set_sid_mode(swe.SIDM_LAHIRI)
FL = swe.FLG_MOSEPH | swe.FLG_SIDEREAL | swe.FLG_SPEED
def jd(y, m, d): return swe.julday(y, m, d, 0.0)
def lon(j, p): return swe.calc_ut(j, p, FL)[0][0] % 360
def spd(j, p): return swe.calc_ut(j, p, FL)[0][3]

# 1. Visti karana and Vaidhrti yoga, hourly over 1950-2000
a, b = jd(1950, 1, 1), jd(2000, 1, 1)
n = v = y = both = 0
j = a
while j < b:
    s, m = lon(j, swe.SUN), lon(j, swe.MOON)
    k = int(((m - s) % 360) // 6)                  # karana index 0..59
    visti = 1 <= k < 57 and (k - 1) % 7 == 6
    vaidhrti = int(((m + s) % 360) // (360 / 27)) == 26
    n += 1; v += visti; y += vaidhrti; both += (visti and vaidhrti)
    j += 1 / 24
print(f"Visti {v/n:.2%}   Vaidhrti {y/n:.2%}   both {both/n:.2%}")

# 2. days within five days of both a Mars station and a Saturn station, 1900-2000
def stations(p, a, b):
    out = []; j = a; prev = spd(j, p)
    while j < b:
        cur = spd(j + 1, p)
        if (prev < 0) != (cur < 0): out.append(j + 0.5)
        prev = cur; j += 1
    return out
a, b = jd(1900, 1, 1), jd(2000, 1, 1)
ms, ss = stations(swe.MARS, a, b), stations(swe.SATURN, a, b)
def near(lst, j):
    i = bisect.bisect(lst, j)
    return min(abs(j - x) for x in lst[max(0, i - 1):i + 1])
d = tot = 0; j = a
while j < b:
    tot += 1; d += (near(ms, j) <= 5 and near(ss, j) <= 5); j += 1
print(f"within 5 days of both stations: {d} days of {tot} ({d/tot:.2%})")

# 3. simple fractions
print(f"Moon in any one naksatra: {1/27:.1%}")
print(f"Saturn within 24' of a gandanta seam: {3*48/60/360:.2%} of the zodiac")
print(f"Mars antara within Rahu's 18 years: {(7*18/120)/18:.1%}")
