"""
main_hybrid.py — Ottimizzazione Ibrida Deterministica (Ridge + MILP)

Script di main per risolvere il problema di assortimento con l'approccio ibrido
deterministico: un modello di Ridge Regression per ogni prodotto predice la domanda
media attesa dato l'assortimento; poi si risolve un MILP deterministico usando
questa domanda predetta.

Prerequisiti (file .pkl richiesti):
  - best_linear_models_list.pkl : lista di modelli Ridge (uno per prodotto + delta_no_buy)
  - scaler_y.pkl                : MinMaxScaler per denormalizzare le previsioni di domanda

Come funziona:
  1. prepare_input_data(SAA_flag=True)            : genera anche scenari SAA per calcolare la domanda media fissa
  2. Calcola domanda_media_fissa                  : usata come parametro di tolleranza SL
  3. AssortmentOptimizer.build_model_hybrid_det() : costruisce il MILP con Ridge embedded
  4. solve()                                      : risolve il modello
  5. export_to_text_hybrid_det()                  : scrive il report su file .txt

Output:
  - analisi_risultati_hybrid_det.txt : report con assortimento ottimale e KPI

Parametri da modificare in main():
  - used_seed                    : seed per la riproducibilità degli scenari
  - n_scenari_domanda_SAA        : numero di scenari su cui calcolare la domanda media 
  - force_recalculate            : flag per stabilire se ricalcolare il file o usare uno già presente
  - nome_file                    : per imposatre il nome del file da usare o svrascrivere
"""

from models import *
from optimization import *
from prepare_data import *

def main():
    data = prepare_input_data(force_recalculate=False, SAA_flag=True, n_scenari_domanda_SAA=300, used_seed=3824, nome_file='dati_progetto_hybrid_det.pkl') #funzione in prepare_data.py: importa il dataset dei prodotti, definisce le costatnti del modello di ottimizzazione, genera le probabilità richiamando le classi del simulazione e fornisce come output tutti i valori utili sia di mercato che di scenario (in questo caso utile per calcolare la domanda attesa su n_scenari_domanda_SAA)
    domanda_media_fissa = np.dot(data["saa_input"]["scenario_prob"], data["saa_input"]["demand_weekly"]) #calcola domanda attesa fissata calcolata su n_scenari_domanda_SAA per usarla come paramentro nel calcolo del livello di servizio 
    no_buy_medio=domanda_media_fissa[-1] #utile come valore nel report finale: è la media su n_scenari_domanda_SAA della no-buy a priori
    domanda_media_fissa=domanda_media_fissa[:-1].sum()

    #istanziamo la classe dell'ottimizzazione e richiamamo i moetodi associati al modello ibrido deterministico
    optimiz = AssortmentOptimizer(data["base"]["prodotti_tab"], data["base"]["sub_matrix"], data["base"]["prezzi"], data["base"]["cost"], data["base"]["holding"], data["base"]["capacita_scaffale_dict"], data["base"]["capacita_frigo_dict"], data["base"]["costo_fisso_scaffale"], data["base"]["penalty_lost_sales"], data["base"]["penale_SL"], data["base"]["SL_target"], flag_shelf=True)
    optimiz.build_model_hybrid_det(demand_tot_mean=domanda_media_fissa, write=True)
    if optimiz.solve(model=optimiz.models["hybrid_det"]):
        optimiz.export_to_text_hybrid_det(no_buy_medio)
        optimiz.close_model("hybrid_det")

if __name__ == "__main__":
    main()

