"""
main_test_shock.py — Test Out-of-Sample con shock di mercato

Variante di main_test_OOS.py che permette di testare la soluzione ottimale
in condizioni di shock di mercato, cioè con una distribuzione dei segmenti
clienti diversa da quella usata durante l'ottimizzazione.

Scenari di shock predefiniti (in fondo al file):

  prob_shock_inflazione = [0.03, 0.03, 0.03, 0.03, 0.70, 0.18]
     Il 70% dei clienti diventa price-sensitive 

  prob_shock_adv = [0.26, 0.02, 0.02, 0.02, 0.36, 0.32]
     La Marca A guadagna molti loyal customer 

  prob_shock_ricchi = [0.1, 0.1, 0.1, 0.1, 0.20, 0.4]
     La quota quality-sensitive aumenta 

Pesi di default (per confronto):
  [0.06, 0.06, 0.06, 0.06, 0.40, 0.36]
  [loyal_A, loyal_B, loyal_C, loyal_D, price_sensitive, quality_sensitive]

Come usare:

  1. Ottenere un assortimento ottimale eseguendo uno dei main_*.py dei modelli di ottimizzazione
  2. Definire il nome del file in cui salvare i risultati che verranno usati per produrre i grafici 
  3. Copiare i vettori 'a' e 'y' ottenuti in 'assortment' e 'quantity' alla fine del file
  4. Modificare il vettore 'prob_scen' nella chiamata main() alla fine del file per scegliere lo scenario di shock da testare.
  5. Eseguire: python main_test_shock.py
 

Output:
  - Stampa a video          : vendite medie, lost service medio, worst-case percentile 5%/95%
  - Risultati_(sxp)_price_* : CSV con dettaglio per scenario x prodotto chiamando 'run_out_of_sample' e 'simulation_results_file'
  - KPI_scenari_price_*     : CSV con KPI aggregati per scenario
  - Grafici                 : distribuzione vendite, distribuzione lost service, heatmap worst case chiamando 'plot_frequences' e 'plot_heap_map'
"""

import sys
import os
cartella_progetto = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
if cartella_progetto not in sys.path:
    sys.path.append(cartella_progetto)
from models import *
from prepare_data import *
from function_test_OOS import *

def main(assortment, quantity,prob_scen):
    file_name_scen="KPI_scen_adv_det"
    file_name_scen_prod="Risultati_(sxp)_T3_det"
    arrivals,Prob,sub_matrix,name_unique_prod=prepare_test_input_data(assortment, prob_scen, used_seed=1234) #funzione presente in prepare_data.py che, dato l'assortimento, fornisce l'intera base per simulare il mercato, chiamando la classe di MarketSimulation, ClientArrivals per fornire probabilità di acquisto per ogni cliente che arriva

    risults_raw_oos=run_out_of_sample(client_arrivals_obj=arrivals,probabilities=Prob,z_assortment=assortment,initial_stock=quantity,subs_matrix=sub_matrix,n_scenarios=300,seed=8888)


    df_kpi_oos,df_det_oos=simulation_results_file(risults_raw_oos, name_unique_prod)

    print("\n=== REPORT PERFORMANCE OUT-OF-SAMPLE (300 Scenari) ===")
    print(f"Vendite Medie Attese: {df_kpi_oos['Vendite Totali (Pezzi)'].mean():.2f} unità")
    print(f"Lost Service Medio:{df_kpi_oos['Lost Service (Domanda Insoddisfatta in store)'].mean():.2f} unità")


    df_det_oos.to_csv(file_name_scen_prod, index=False)
    df_kpi_oos.to_csv(file_name_scen, index=False)

    worst_case_sales=df_kpi_oos['Vendite Totali (Pezzi)'].quantile(0.05)
    worst_case_service=df_kpi_oos['Lost Service (Domanda Insoddisfatta in store)'].quantile(0.95)

    print(f"Worst-Case Sales (Percentile 5%): {worst_case_sales:.2f} unità")
    print(f"Worst-Case Lost Service (Percentile 95%): {worst_case_service:.2f} unità")

    #plottiamo le frequenze di vendita e di lost dei prodotti
    plot_frequences(df_kpi_oos)

    #vediamo come si comportano i primi 30 prodotti nei primi 15 scenari simulati
    top_prod=name_unique_prod[:15]
    df_filter=df_det_oos[df_det_oos['Prodotto'].isin(top_prod)]
    plot_heap_map(df_filter,'Mappa Criticità: Domanda Persa per Prodotto Specifico nei primi 15 Scenari','Identificativo Univoco Prodotto','Scenari di Test Out-of-Sample')

    top_prod= name_unique_prod[15:30]
    df_filter= df_det_oos[df_det_oos['Prodotto'].isin(top_prod)]
    plot_heap_map(df_filter,'Mappa Criticità: Domanda Persa per Prodotto Specifico nei primi 15 Scenari','Identificativo Univoco Prodotto','Scenari di Test Out-of-Sample')

    #vediamo i casi peggiori negli scenari simulati
    df_scenari_critici = df_kpi_oos.sort_values(by='Lost Service (Domanda Insoddisfatta in store)', ascending=False)
    scenarios_worst = df_scenari_critici['Scenario'].head(15).tolist()
    prod_critics = df_det_oos.groupby('Prodotto')['Domanda Persa (Prodotto)'].sum().nlargest(15).index.tolist()
    # Teniamo solo le righe che corrispondono ai 15 scenari peggiori E ai 15 prodotti peggiori
    df_filter = df_det_oos[(df_det_oos['Scenario'].isin(scenarios_worst)) & (df_det_oos['Prodotto'].isin(prod_critics))]
    plot_heap_map(df_filter,'Worst-Case Analysis: I 15 Prodotti più critici nei 15 Scenari peggiori','ID e Descrizione Prodotto','Scenari (Ordinati dal peggiore in assoluto verso destra)',scenarios_worst)

if __name__ == "__main__":
    #assortment=[0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    #assortment=[0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]
    #quantity=[0, 47, 19, 47, 0, 20, 29, 0, 49, 34, 0, 53, 41, 0, 62, 0, 0, 0, 0, 10, 0, 8, 0, 12, 0, 0, 0, 0, 1, 2, 192, 0, 46, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 5, 0, 0, 11, 0, 41, 12, 0, 45, 4, 0, 10, 4, 0, 6, 16, 0, 43, 0, 43, 34, 0, 4, 0, 5, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 56, 52, 0, 33, 0, 45, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]
    #quantity=[0, 47, 20, 47, 0, 20, 29, 0, 49, 34, 0, 53, 41, 0, 63, 0, 0, 0, 0, 10, 0, 8, 0, 12, 0, 0, 0, 0, 1, 2, 192, 0, 48, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 5, 0, 0, 11, 0, 36, 12, 0, 45, 4, 0, 10, 4, 0, 6, 16, 0, 43, 0, 43, 34, 0, 4, 0, 5, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 57, 52, 0, 33, 0, 45, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0]
    #quantity=[0, 47, 23, 45, 0, 25, 29, 0, 49, 34, 0, 52, 42, 0, 63, 0, 0, 0, 0, 9, 0, 7, 0, 10, 0, 0, 0, 0, 0, 0, 200, 0, 45, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 11, 0, 41, 13, 0, 42, 0, 0, 10, 8, 0, 6, 16, 0, 43, 0, 43, 29, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 55, 52, 0, 26, 0, 45, 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
    assortment=[0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1]
    quantity=[0, 0, 0, 0, 0, 0, 0, 0, 79, 58, 0, 88, 72, 0, 109, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 10, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 14, 0, 19, 0, 33, 39, 0, 65, 45, 0, 72, 0, 0, 0, 18, 0, 25, 0, 0, 74, 0, 0, 0, 0, 18, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 2, 0, 0, 0, 2, 0, 2, 0, 0, 68, 0, 0, 97, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 6, 0, 8] 

    prob_shock_inflazione=[0.03, 0.03, 0.03, 0.03, 0.70, 0.18]
    prob_shock_adv=[0.26, 0.02, 0.02, 0.02, 0.36, 0.32]
    prob_shock_ricchi=[0.1, 0.1, 0.1, 0.1, 0.20, 0.4]
    main(assortment, quantity, prob_shock_ricchi)