"""Tiny CPU LSTM training demonstration on synthetic data, not a market predictor.
Requires pandas, numpy, scikit-learn and torch. Run next to ml_lab.py.
"""
from pathlib import Path
import json
import numpy as np
import torch
from sklearn.metrics import accuracy_score
from ml_lab import prepare

def windows(frame, columns, mean, std, length=20):
    x=(frame[columns].to_numpy()-mean)/std
    xs=[];ys=[]
    for i in range(length-1,len(frame)):
        xs.append(x[i-length+1:i+1]);ys.append(frame.y.iloc[i])
    return torch.tensor(np.array(xs),dtype=torch.float32),torch.tensor(ys,dtype=torch.float32)

if __name__=="__main__":
    torch.manual_seed(20261016); torch.set_num_threads(1)
    train,test,cols=prepare()
    mean=train[cols].mean().to_numpy();std=train[cols].std().to_numpy()
    std=np.where(std>0,std,1)
    x,y=windows(train,cols,mean,std);xt,yt=windows(test,cols,mean,std)
    assert x.shape[1:]==(20,3) and len(xt)>0
    lstm=torch.nn.LSTM(3,8,batch_first=True); head=torch.nn.Linear(8,1)
    optim=torch.optim.Adam(list(lstm.parameters())+list(head.parameters()),lr=0.01)
    criterion=torch.nn.BCEWithLogitsLoss(); losses=[]
    for epoch in range(8):
        optim.zero_grad();out,_=lstm(x);logits=head(out[:,-1,:]).squeeze(-1)
        loss=criterion(logits,y);loss.backward();optim.step();losses.append(float(loss.detach()))
    lstm.eval();head.eval()
    with torch.no_grad():
        out,_=lstm(xt);pred=(head(out[:,-1,:]).squeeze(-1)>0).int().numpy()
    metrics={"kind":"synthetic CPU demo only","input_shape":list(x.shape),"hidden":8,"epochs":8,
             "losses":losses,"test_n":len(yt),"accuracy":accuracy_score(yt.numpy(),pred),
             "baseline_accuracy":accuracy_score(yt.numpy(),np.full(len(yt),int(y.mean()>=0.5))),
             "split":"independent windows within purged chronological train/test; scaler fit on train only",
             "no_claim":"not real-market prediction, no trading returns or production deployment"}
    outdir=Path("lstm-results");outdir.mkdir(exist_ok=True)
    (outdir/"metrics.json").write_text(json.dumps(metrics,indent=2),encoding="utf-8")
    print(json.dumps(metrics))
