from typing import List
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import pandas as pd
from sklearn.preprocessing import StandardScaler

app = FastAPI(title="Model API", description="API for appliances prediction")


class PostData(BaseModel):
    """postされてくるリクエストの型を定義する
    """
    data: List[List[float]]
    index: List[str]
    columns: List[str]


@app.on_event('startup')
def load_model_from_pickle():
    """サーバー立ち上げ時に呼ばれる処理
    """
    try:
        model = pd.read_pickle('models/model.pkl')
        xscl, yscl = pd.read_pickle('models/params.pkl')
        return model, xscl, yscl
    except Exception as e:
        raise ValueError(e)

# 起動時にのちの処理に必要な変数受け取っておく
model, xscl, yscl = load_model_from_pickle()


def preprocess(df):
    """受け取ったデータに対して前処理を行う関数
    """
    df['am/pm_PM'] = [1 if c == 'PM' else 0 for c in df.index.strftime('%p')]
    df = xscl.transform(df)
    return df

def postprocess(predictions):
    """受け取ったデータに対して後処理を行う関数
    """
    # 正規化を逆変換
    return yscl.inverse_transform(predictions.reshape(-1, 1))
    
    


@app.post('/predict')
async def predict(postdata: PostData):
    """predictにPOSTリクエストを投げたときの処理
    """
    try:
        data = postdata.data
        index = postdata.index
        columns = postdata.columns
        
        # 前処理しやすいように一度元のDataFrameに変換
        df = pd.DataFrame(data, index=pd.to_datetime(index), columns=columns)
        
        # 前処理
        df = preprocess(df)
        predictions = model.predict(df)
        
        predictions = postprocess(predictions)
        
        # 呼び出し元に返す
        return {"predictions": predictions.tolist()}
    except Exception as e:
        raise HTTPException(status_code=400, detail=str(e))