import numpy as np
import pandas as pd
import datetime, time
import random

# ----------------------------------------------------------
# SETTINGS
# ----------------------------------------------------------
start_date = datetime.datetime(2024, 4, 1, 0, 0, 0)
end_date   = datetime.datetime(2024, 9, 30, 23, 0, 0)

# hourly increments
delta = datetime.timedelta(hours=1)

rows = []

# ----------------------------------------------------------
# HELPER FUNCTIONS FOR WEATHER MODELLING
# ----------------------------------------------------------

def seasonal_temp_old(day_of_year, hour):
    """
    Temperature model:
    - Warmer in July–Aug
    - Cooler in April & September
    - Daily cycle: peak at 15:00
    """
    # seasonal baseline
    season_amp = 10  # magnitude of seasonal movement
    # center warm peak around day 220 (August)
    season = 22 + season_amp * np.cos((day_of_year - 220) / 58)

    # daily cycle: sinusoid over 24h
    daily = 6 * np.sin((hour - 15) / 24 * 2 * np.pi)

    return season + daily

def seasonal_temp(day,hour):
    """
    Compute seasonal temperature for a given day-of-year (1–365)
    using month-specific cosine formulas provided by the user.
    Each month uses:
        T(day) = A_month * cos(pi/200 * day - pi) + B_month
    MONTH EQUATIONS:
    April (day 91–120):
        T = 12.4 * cos(pi/200 * day - pi) + 10.6
    May (day 121–151):
        T = 14.4 * cos(pi/200 * day - pi) + 13.6
    June (day 152–181):
        T = 17.4 * cos(pi/200 * day - pi) + 18.6
    July (day 182–212):
        T = 18.4 * cos(pi/200 * day - pi) + 19.6
    August (day 213–243):
        T = 18.4 * cos(pi/200 * day - pi) + 18.6
    September (day 244–273):
        T = 15.4 * cos(pi/200 * day - pi) + 17.6
    """
    season=0
    # April
    if 91 <= day <= 120:
        season= 12.4 * np.cos(np.pi/200 * day - np.pi) + 10.6
    # May
    if 121 <= day <= 151:
        season= 14.4 * np.cos(np.pi/200 * day - np.pi) + 13.6
    # June
    if 152 <= day <= 181:
        season= 17.4 * np.cos(np.pi/200 * day - np.pi) + 18.6
    # July
    if 182 <= day <= 212:
        season= 18.4 * np.cos(np.pi/200 * day - np.pi) + 19.6
    # August
    if 213 <= day <= 243:
        season= 18.4 * np.cos(np.pi/200 * day - np.pi) + 18.6
    # September
    if 244 <= day <= 274:
        season= 15.4 * np.cos(np.pi/200 * day - np.pi) + 17.6
    # Outside Apr–Sep not defined → return 0 (or choose a winter model)
    # daily cycle: sinusoid over 24h
    if season==0: 
        daily=0
    else:
        daily = 6 * np.sin((hour - 15) / 24 * 2 * np.pi)
    return season + daily

def seasonal_humidity(temp):
    """
    Humidity inversely related to temperature with noise.
    """
    base = 80 - (temp - 20) * 1.5
    return np.clip(base, 20, 100)
    #return np.clip(base + np.random.normal(0, 5), 20, 100)

def seasonal_humidity2(temp):
    """
    Humidity inversely related to temperature with uniform noise.

    Original model:
        base = 80 - (temp - 20) * 1.5
        humidity = base + noise
        noise was N(0,5)

    Updated:
        noise = uniform(-5, +5)
    """
    base = 80 - (temp - 20) * 1.5
    noise = np.random.uniform(-5, 5)      # uniform random noise
    value = base + noise
    return np.clip(value, 20, 100)         # humidity realistic bounds

def leaf_wetness(humidity, hour):
    """
    Leaf wetness increases at night when humidity is high.
    """
    night_factor = 1.0 if (hour < 7 or hour > 20) else 0.4
    wet = (humidity / 100.0) * night_factor + np.random.normal(0, 0.02)
    return np.clip(wet, 0.0, 1.0)


def wind_speed(hour):
    """
    Wind higher in afternoon, lower at night.
    """
    base = 2.0 + 1.5 * np.sin((hour - 14) / 24 * 2 * np.pi)  # peak mid-afternoon
    gust = np.random.normal(0, 0.5)
    return max(0, base + gust)


# ----------------------------------------------------------
# GENERATE WEATHER DATA
# ----------------------------------------------------------

date = start_date
counter = 0
print("Generating hourly samples...")

while date <= end_date:
    ts = int(time.mktime(date.timetuple()))
    hour = date.hour
    day_of_year = date.timetuple().tm_yday

    # ---------- TEMPERATURE ----------
    temp = seasonal_temp(day_of_year, hour)

    # Random weather cooling/warming events
    if random.random() < 0.02:  # 2% chance sudden cold snap
        temp -= random.uniform(2, 6)
    if random.random() < 0.02:  # 2% chance sudden warm spell
        temp += random.uniform(2, 5)

    # ---------- HUMIDITY ----------
    hum = seasonal_humidity(temp)

    # Occasional humidity spikes (storms)
    if random.random() < 0.03:
        hum = min(100, hum + random.uniform(10, 25))

    # ---------- LEAF WETNESS ----------
    leaf = leaf_wetness(hum, hour)

    # ---------- WIND SPEED ----------
    wind = wind_speed(hour)

    # occasional windy days
    if random.random() < 0.03:
        wind += random.uniform(2, 5)

    rows.append([ts, round(temp, 2), round(hum, 2), round(leaf, 3), round(wind, 2)])

    date += delta
    counter += 1

print("Generated", counter, "rows.")


# ----------------------------------------------------------
# SAVE TO CSV
# ----------------------------------------------------------
df = pd.DataFrame(rows, columns=["timestamp", "temp", "hum", "leaf", "wind"])
df.to_csv("training_data.csv", index=False, header=False)

print("Saved training_data.csv!")

