"""Rolling one-hour-ahead evaluation with observations available at each origin."""
from pathlib import Path
import pandas as pd
from sklearn.model_selection import TimeSeriesSplit
from sklearn.pipeline import make_pipeline
from sklearn.preprocessing import StandardScaler
from sklearn.linear_model import Ridge
from sklearn.metrics import mean_absolute_error
root=Path(__file__).resolve().parent
frame=pd.read_csv(root/'demand_hourly_clean.csv',parse_dates=['timestamp_utc']).set_index('timestamp_utc').sort_index()
if not frame.index.is_unique:raise ValueError('Duplicate timestamps')
if not (frame.index.to_series().diff().dropna()==pd.Timedelta(hours=1)).all():
 raise ValueError('Expected a continuous hourly series')
if frame.isna().any().any():raise ValueError('Missing data')
frame['lag24']=frame['demand_m3_h'].shift(24)
frame['lag168']=frame['demand_m3_h'].shift(168)
frame['hour']=frame.index.hour
frame['weekday']=frame.index.dayofweek
frame=frame.dropna()
features=['lag24','lag168','hour','weekday']
train=frame.iloc[:-14*24];test=frame.iloc[-14*24:]
cv=TimeSeriesSplit(n_splits=3,test_size=7*24)
scores={}
for alpha in [0.1,1.0,10.0]:
 errors=[]
 for fit_idx,val_idx in cv.split(train):
  model=make_pipeline(StandardScaler(),Ridge(alpha=alpha))
  model.fit(train.iloc[fit_idx][features],train.iloc[fit_idx]['demand_m3_h'])
  pred=model.predict(train.iloc[val_idx][features])
  errors.append(mean_absolute_error(train.iloc[val_idx]['demand_m3_h'],pred))
 scores[alpha]=sum(errors)/len(errors)
best=min(scores,key=scores.get)
model=make_pipeline(StandardScaler(),Ridge(alpha=best))
model.fit(train[features],train['demand_m3_h'])
pred=model.predict(test[features])
observed=test['demand_m3_h']
print('Chosen alpha:',best)
for name,forecast in [('Yesterday',test['lag24']),('Last week',test['lag168']),('Ridge',pred)]:
 print(name,'holdout MAE m3/h:',round(mean_absolute_error(observed,forecast),4))
peak=observed>=train['demand_m3_h'].quantile(.90)
print('Ridge peak-period MAE m3/h:',round(mean_absolute_error(observed[peak],pred[peak]),4))
print('Negative predictions:',int((pred<0).sum()))
test.assign(prediction_m3_h=pred)[['demand_m3_h','prediction_m3_h','lag24','lag168']].to_csv(root/'forecast_results.csv')
