library(readr)
library(fpp3)
library(zoo)
library(dplyr)
library(tidyr)
library(lubridate)
library(purrr)
library(rugarch)
library(tictoc)
library(stringr)

library(broom)
library(knitr)

add_weekday_dummies <- function(df) {
  df %>%
    mutate(
      giorno_num = wday(Data, week_start = 1),
      
      ```
      martedi   = if_else(giorno_num == 2, 1, 0),
      mercoledi = if_else(giorno_num == 3, 1, 0),
      giovedi   = if_else(giorno_num == 4, 1, 0),
      venerdi   = if_else(giorno_num == 5, 1, 0),
      sabato    = if_else(giorno_num == 6, 1, 0),
      domenica  = if_else(giorno_num == 7, 1, 0)
    ) %>%
    select(-giorno_num)
  ```
  
}

dataItalia <- read_csv("C:\Users\Matteo\OneDrive\Desktop\Tesi2\dataset\dfItalia.csv")
dataFrancia <- read_csv("C:\Users\Matteo\OneDrive\Desktop\Tesi2\dataset\dfFrancia.csv")
dataGermania <- read_csv("C:\Users\Matteo\OneDrive\Desktop\Tesi2\dataset\dfGermania.csv")
dataDanimarca <- read_csv("C:\Users\Matteo\OneDrive\Desktop\Tesi2\dataset\dfDanimarca.csv")

dfItalia <- dataItalia %>%
  as_tsibble(index = Data)
dfFrancia <- dataFrancia %>%
  as_tsibble(index = Data)
dfGermania <- dataGermania %>%
  as_tsibble(index = Data)
dfDanimarca <- dataDanimarca %>%
  as_tsibble(index = Data)

has_gaps(dfItalia)
has_gaps(dfFrancia)
has_gaps(dfGermania)
has_gaps(dfDanimarca)

date_duplicate <- dfItalia %>%
  count(Data) %>%
  filter(n > 1)
print(date_duplicate)
date_duplicate <- dfFrancia %>%
  count(Data) %>%
  filter(n > 1)
print(date_duplicate)
date_duplicate <- dfGermania %>%
  count(Data) %>%
  filter(n > 1)
print(date_duplicate)
date_duplicate <- dfDanimarca %>%
  count(Data) %>%
  filter(n > 1)
print(date_duplicate)

dataPUN <- read.csv("C:\Users\Matteo\OneDrive\Desktop\Tesi\Dati\PUN.csv")

dataPUN$DateTime <- as.POSIXct(
  paste(dataPUN$Data, sprintf("%02d:00:00", dataPUN$Ora - 1)),
  format = "%d/%m/%Y %H:%M:%S",
  tz = "UTC"
)

dataPUN <- dataPUN[, !names(dataPUN) %in% c("Data", "Ora")]

sum(is.na(dataPUN$DateTime))

date_parsed <- as.POSIXct(
  dataPUN$DateTime,
  format = "%Y-%m-%d %H:%M:%S",
  tz = "UTC"
)
date_errate <- dataPUN$DateTime[is.na(date_parsed)]
print(date_errate)

dataPUN$X..MWh <- as.numeric(gsub(",", ".", dataPUN$X..MWh))

sum(duplicated(dataPUN$DateTime))

dataPUN <- dataPUN %>%
  group_by(DateTime) %>%
  summarise(
    X..MWh = mean(X..MWh, na.rm = TRUE),
    .groups = "drop"
  )

dataPUN <- dataPUN |> rename(Price = X..MWh)

dfPun <- as_tsibble(dataPUN, index = DateTime)

tsibble::scan_gaps(dfPun)

dfPun <- dfPun |>
  fill_gaps() |>
  mutate(
    Price = zoo::na.approx(Price)
  )

dfItalia <- dfItalia %>%
  left_join(dfPun %>% select(DateTime, Price), by = c("Data" = "DateTime")) %>%
  rename(PUN = Price)

dfItalia <- dfItalia %>%
  rename(Prezzo=PUN)

dfFrancia <- dfFrancia %>%
  rename(Prezzo=Giorno_prezzo_spot_avanti_FR)

dfGermania <- dfGermania %>%
  rename(Prezzo=`Giorno_prezzo_spot_avanti_DE-LU`)

dfDanimarca <- dfDanimarca %>%
  rename(Prezzo=Giorno_prezzo_spot_avanti_DK1)

colSums(is.na(dataItalia))
colSums(is.na(dataFrancia))
colSums(is.na(dataGermania))
colSums(is.na(dataDanimarca))

dfItalia <- dfItalia %>%
  mutate(across(where(is.numeric), ~ na.approx(., na.rm = FALSE, rule = 2)))
dfFrancia <- dfFrancia %>%
  mutate(across(where(is.numeric), ~ na.approx(., na.rm = FALSE, rule = 2)))
dfGermania <- dfGermania %>%
  mutate(across(where(is.numeric), ~ na.approx(., na.rm = FALSE, rule = 2)))
dfDanimarca <- dfDanimarca %>%
  mutate(across(where(is.numeric), ~ na.approx(., na.rm = FALSE, rule = 2)))

sum(is.na(dfItalia))
sum(is.na(dfFrancia))
sum(is.na(dfGermania))
sum(is.na(dfDanimarca))

dfItalia <- dfItalia %>%
  mutate(
    Giorno = date(Data),
    Ora_ = hour(Data)
  )
dfItalia <- dfItalia %>%
  mutate(
    Ora_ = factor(Ora_),
    Giorno_settimana = factor(
      wday(Data, label = TRUE, week_start = 1),
      ordered = FALSE
    )
  )
dfItalia <- dfItalia %>%
  filter(Giorno>="2023-01-01")

dfFrancia <- dfFrancia %>%
  mutate(
    Giorno = date(Data),
    Ora_ = hour(Data)
  )
dfFrancia <- dfFrancia %>%
  mutate(
    Ora_ = factor(Ora_),
    Giorno_settimana = factor(
      wday(Data, label = TRUE, week_start = 1),
      ordered = FALSE
    )
  )
dfFrancia <- dfFrancia %>%
  filter(Giorno>="2023-01-01")

dfGermania <- dfGermania %>%
  mutate(
    Giorno = date(Data),
    Ora_ = hour(Data)
  )
dfGermania <- dfGermania %>%
  mutate(
    Ora_ = factor(Ora_),
    Giorno_settimana = factor(
      wday(Data, label = TRUE, week_start = 1),
      ordered = FALSE
    )
  )
dfGermania <- dfGermania %>%
  filter(Giorno>="2023-01-01")

dfDanimarca <- dfDanimarca %>%
  mutate(
    Giorno = date(Data),
    Ora_ = hour(Data)
  )
dfDanimarca <- dfDanimarca %>%
  mutate(
    Ora_ = factor(Ora_),
    Giorno_settimana = factor(
      wday(Data, label = TRUE, week_start = 1),
      ordered = FALSE
    )
  )
dfDanimarca <- dfDanimarca %>%
  filter(Giorno>="2023-01-01")

dfItalia <- add_weekday_dummies(dfItalia)
dfFrancia <- add_weekday_dummies(dfFrancia)
dfGermania <- add_weekday_dummies(dfGermania)
dfDanimarca <- add_weekday_dummies(dfDanimarca)

names(dfItalia)
names(dfFrancia)
names(dfGermania)
names(dfDanimarca)

dummy_settimana <- c(
  "sabato",
  "domenica"
)

xreg_italia <- c(
  "Carico",
  "Rinnovabile",
  "Non_Rinnovabile",
  "Commercio_transfrontaliero_di_energia_elettrica",
  "Quote_di_emissioni_europee_di_CO2_Auction_EU",
  dummy_settimana
)

xreg_francia <- c(
  "Carico",
  "Rinnovabile",
  "Non_Rinnovabile",
  "Nucleare",
  "Commercio_transfrontaliero_di_energia_elettrica",
  "Quote_di_emissioni_europee_di_CO2_Auction_EU",
  dummy_settimana
)

xreg_germania <- c(
  "Carico",
  "Rinnovabile",
  "Non_Rinnovabile",
  "Commercio_transfrontaliero_di_energia_elettrica",
  "Quote_di_emissioni_europee_di_CO2_Auction_EU",
  dummy_settimana
)

xreg_danimarca <- c(
  "Carico",
  "Rinnovabile",
  "Non_Rinnovabile",
  "Commercio_transfrontaliero_di_energia_elettrica",
  "Quote_di_emissioni_europee_di_CO2_Auction_EU",
  dummy_settimana
)

tsMaking <- function(dataset, ora) {
  
  dataset %>%
    as_tibble() %>%
    filter(Ora_ == ora) %>%
    arrange(Giorno) %>%
    mutate( diffPrezzo = Prezzo - lag(Prezzo)) %>%
    filter(!is.na(diffPrezzo)) %>%
    select(-Data)
}

tsMakingfpp3 <- function(dataset, ora, xreg_cols) {
  
  dataset %>%
    as_tibble() %>%
    filter(Ora_ == ora) %>%
    arrange(Giorno) %>%
    mutate(
      diffPrezzo = Prezzo - lag(Prezzo)
    ) %>%
    filter(!is.na(diffPrezzo)) %>%
    select(
      Giorno,
      Prezzo,
      diffPrezzo,
      all_of(xreg_cols)
    ) %>%
    as_tsibble(index = Giorno)
}

bt <- function(x) {
  paste0("`", x, "`")
}

make_arimax_formula <- function(xreg_cols) {
  
  regressori <- paste(bt(xreg_cols), collapse = " + ")
  
  formula_txt <- paste0(
    "diffPrezzo ~ ",
    regressori,
    " + pdq(1, 0, 1) + PDQ(0, 0, 0)"
  )
  
  as.formula(formula_txt)
}

make_cv_future_data <- function(data_ts, cv_data, xreg_cols, refit_every) {
  
  fold_ends <- cv_data %>%
    as_tibble() %>%
    group_by(.id) %>%
    summarise(
      last_train = max(Giorno),
      .groups = "drop"
    )
  
  future_data <- fold_ends %>%
    mutate(
      future = map(
        last_train,
        function(last_day) {
          data_ts %>%
            as_tibble() %>%
            filter(Giorno > last_day) %>%
            slice_head(n = refit_every) %>%
            select(
              Giorno,
              all_of(xreg_cols)
            )
        }
      )
    ) %>%
    select(.id, future) %>%
    tidyr::unnest(future) %>%
    as_tsibble(index = Giorno, key = .id)
  
  future_data
}

arimaCV <- function(data_ts, xreg_cols) {
  
  target_col <- "diffPrezzo"
  start_date <- "2024-01-01"
  refit_every <- 1
  
  start_date <- ymd(start_date)
  
  n_start <- data_ts %>%
    filter(Giorno < start_date) %>%
    nrow()
  
  cv_data <- data_ts %>%
    stretch_tsibble(
      .init = n_start,
      .step = refit_every
    )
  
  arimax_formula <- make_arimax_formula(xreg_cols)
  
  fit <- cv_data %>%
    model(
      arima = ARIMA(arimax_formula)
    )
  
  future_data <- make_cv_future_data(
    data_ts = data_ts,
    cv_data = cv_data,
    xreg_cols = xreg_cols,
    refit_every = refit_every
  )
  
  fc <- fit %>%
    forecast(new_data = future_data)
  
  fc_df <- fc %>%
    as_tibble() %>%
    select(
      .id,
      Giorno,
      Mu = .mean
    )
  
  actual_df <- data_ts %>%
    as_tibble() %>%
    select(
      Giorno,
      actual = all_of(target_col)
    )
  
  results <- fc_df %>%
    inner_join(actual_df, by = "Giorno") %>%
    mutate(
      errore = actual - Mu,
      abs_error = abs(errore),
      squared_error = errore^2
    ) %>%
    select(
      Giorno,
      actual,
      Mu,
      errore,
      abs_error,
      squared_error,
      .id
    )
  
  return(
    list(
      fit = fit,
      forecast = fc,
      results = results
    )
  )
}

garchCV <- function(data_ts) {
  target_col = "diffPrezzo"
  start_date = "2024-01-01"
  
  start_date <- ymd(start_date)
  
  n_start <- data_ts %>%
    filter(Giorno < start_date) %>%
    nrow()
  
  y <- as.numeric(data_ts[[target_col]])
  
  spec <- ugarchspec(
    variance.model = list(
      model = "sGARCH",
      garchOrder = c(1, 1)
    ),
    mean.model = list(
      armaOrder = c(0, 1),
      include.mean = TRUE
    ),
    distribution.model = "std"
  )
  
  roll <- ugarchroll(
    spec = spec,
    data = y,
    n.ahead = 1,
    n.start = n_start,
    refit.every = 90,
    refit.window = "recursive",
    solver = "hybrid",
    calculate.VaR = FALSE,
    keep.coef = TRUE
  )
  
  roll_df <- as.data.frame(roll)
  
  test_dates <- data_ts %>%
    slice((n_start + 1):n()) %>%
    select(Giorno, actual = all_of(target_col))
  
  results <- bind_cols(
    test_dates,
    roll_df
  )
  
  return(
    list(
      roll = roll,
      results = results
    )
  )
}

etsCV <- function(data_ts) {
  
  target_col <- "diffPrezzo"
  start_date <- "2024-01-01"
  refit_every <- 1
  
  start_date <- ymd(start_date)
  
  n_start <- data_ts %>%
    filter(Giorno < start_date) %>%
    nrow()
  
  cv_data <- data_ts %>%
    stretch_tsibble(
      .init = n_start,
      .step = refit_every
    )
  
  fit <- cv_data %>%
    model(
      ets = ETS(
        diffPrezzo ~ error("A") + trend("A") + season("A", period = 7)
      )
    )
  
  fc <- fit %>%
    forecast(h = refit_every)
  
  fc_df <- fc %>%
    as_tibble() %>%
    select(
      .id,
      Giorno,
      Mu = .mean
    )
  
  actual_df <- data_ts %>%
    as_tibble() %>%
    select(
      Giorno,
      actual = all_of(target_col)
    )
  
  results <- fc_df %>%
    inner_join(actual_df, by = "Giorno") %>%
    mutate(
      errore = actual - Mu,
      abs_error = abs(errore),
      squared_error = errore^2
    ) %>%
    select(
      Giorno,
      actual,
      Mu,
      errore,
      abs_error,
      squared_error,
      .id
    )
  
  return(
    list(
      fit = fit,
      forecast = fc,
      results = results
    )
  )
}

arimaRawCV <- function(data_ts) {
  
  target_col <- "diffPrezzo"
  start_date <- "2024-01-01"
  refit_every <- 1
  
  start_date <- ymd(start_date)
  
  n_start <- data_ts %>%
    filter(Giorno < start_date) %>%
    nrow()
  
  cv_data <- data_ts %>%
    stretch_tsibble(
      .init = n_start,
      .step = refit_every
    )
  
  fit <- cv_data %>%
    model(
      arimaRaw = ARIMA(
        diffPrezzo ~ pdq(1, 0, 1) + PDQ(0, 0, 0)
      )
    )
  
  fc <- fit %>%
    forecast(h = refit_every)
  
  fc_df <- fc %>%
    as_tibble() %>%
    select(
      .id,
      Giorno,
      Mu = .mean
    )
  
  actual_df <- data_ts %>%
    as_tibble() %>%
    select(
      Giorno,
      actual = all_of(target_col)
    )
  
  results <- fc_df %>%
    inner_join(actual_df, by = "Giorno") %>%
    mutate(
      errore = actual - Mu,
      abs_error = abs(errore),
      squared_error = errore^2
    ) %>%
    select(
      Giorno,
      actual,
      Mu,
      errore,
      abs_error,
      squared_error,
      .id
    )
  
  return(
    list(
      fit = fit,
      forecast = fc,
      results = results
    )
  )
}

tic("italia")

itArima <- vector("list", 24)
itArimaRaw <- vector("list", 24)
itGarch <- vector("list", 24)
itEts <- vector("list", 24)

for (i in 0:23) {
  
  cat("Italia - ora", i, "\n")
  
  ts_i <- tsMakingfpp3(
    dataset = dfItalia,
    ora = i,
    xreg_cols = xreg_italia
  )
  
  itArima[[i + 1]] <- arimaCV(
    data_ts = ts_i,
    xreg_cols = xreg_italia
  )
  
  itArimaRaw[[i + 1]] <- arimaRawCV(
    data_ts = ts_i
  )
  
  itGarch[[i + 1]] <- garchCV(
    data_ts = ts_i
  )
  
  itEts[[i + 1]] <- etsCV(
    data_ts = ts_i
  )
}
toc()

tic("francia")

frArima <- vector("list", 24)
frArimaRaw <- vector("list", 24)
frGarch <- vector("list", 24)
frEts <- vector("list", 24)

for (i in 0:23) {
  
  cat("Francia - ora", i, "\n")
  
  ts_i <- tsMakingfpp3(
    dataset = dfFrancia,
    ora = i,
    xreg_cols = xreg_francia
  )
  
  frArima[[i + 1]] <- arimaCV(
    data_ts = ts_i,
    xreg_cols = xreg_francia
  )
  
  frArimaRaw[[i + 1]] <- arimaRawCV(
    data_ts = ts_i
  )
  
  frGarch[[i + 1]] <- garchCV(
    data_ts = ts_i
  )
  
  frEts[[i + 1]] <- etsCV(
    data_ts = ts_i
  )
}
toc()

tic("germania")

geArima <- vector("list", 24)
geArimaRaw <- vector("list", 24)
geGarch <- vector("list", 24)
geEts <- vector("list", 24)

for (i in 0:23) {
  
  cat("Germania - ora", i, "\n")
  
  ts_i <- tsMakingfpp3(
    dataset = dfGermania,
    ora = i,
    xreg_cols = xreg_germania
  )
  
  geArima[[i + 1]] <- arimaCV(
    data_ts = ts_i,
    xreg_cols = xreg_germania
  )
  
  geArimaRaw[[i + 1]] <- arimaRawCV(
    data_ts = ts_i
  )
  
  geGarch[[i + 1]] <- garchCV(
    data_ts = ts_i
  )
  
  geEts[[i + 1]] <- etsCV(
    data_ts = ts_i
  )
}
toc()

tic("danimarca")

deArima <- vector("list", 24)
deArimaRaw <- vector("list", 24)
deGarch <- vector("list", 24)
deEts <- vector("list", 24)

for (i in 0:23) {
  
  cat("Danimarca - ora", i, "\n")
  
  ts_i <- tsMakingfpp3(
    dataset = dfDanimarca,
    ora = i,
    xreg_cols = xreg_danimarca
  )
  
  deArima[[i + 1]] <- arimaCV(
    data_ts = ts_i,
    xreg_cols = xreg_danimarca
  )
  
  deArimaRaw[[i + 1]] <- arimaRawCV(
    data_ts = ts_i
  )
  
  deGarch[[i + 1]] <- garchCV(
    data_ts = ts_i
  )
  
  deEts[[i + 1]] <- etsCV(
    data_ts = ts_i
  )
}
toc()

estrai_forecast_originale <- function(model_obj, data_ts, nome_modello) {
  
  if (is.null(model_obj) || is.null(model_obj$results)) {
    return(tibble())
  }
  
  dati_prezzo <- data_ts %>%
    as_tibble() %>%
    mutate(Giorno = as_date(Giorno)) %>%
    arrange(Giorno) %>%
    select(Giorno, Prezzo) %>%
    mutate(
      Prezzo_lag = lag(Prezzo)
    )
  
  res <- model_obj$results %>%
    as_tibble() %>%
    mutate(
      Giorno = as_date(Giorno),
      Mu = as.numeric(Mu)
    )
  
  if (".id" %in% names(res)) {
    
    ```
    res <- res %>%
      mutate(.id = as.character(.id)) %>%
      select(.id, Giorno, actual, Mu) %>%
      arrange(.id, Giorno)
    
    fold_info <- res %>%
      group_by(.id) %>%
      summarise(
        primo_giorno_forecast = min(Giorno),
        .groups = "drop"
      )
    
    get_prezzo_iniziale <- function(primo_giorno) {
      
      prezzo_iniziale <- dati_prezzo %>%
        filter(Giorno < primo_giorno) %>%
        arrange(desc(Giorno)) %>%
        slice(1) %>%
        pull(Prezzo)
      
      if (length(prezzo_iniziale) == 0) {
        NA_real_
      } else {
        prezzo_iniziale
      }
    }
    
    fold_info <- fold_info %>%
      mutate(
        prezzo_iniziale = map_dbl(
          primo_giorno_forecast,
          get_prezzo_iniziale
        )
      )
    
    forecast_originale <- res %>%
      left_join(fold_info, by = ".id") %>%
      group_by(.id) %>%
      arrange(Giorno, .by_group = TRUE) %>%
      mutate(
        Prezzo_forecast = prezzo_iniziale + cumsum(Mu)
      ) %>%
      ungroup() %>%
      left_join(
        dati_prezzo %>% select(Giorno, Prezzo),
        by = "Giorno"
      ) %>%
      transmute(
        Giorno,
        Prezzo_reale = Prezzo,
        Modello = nome_modello,
        Prezzo_forecast
      )
    ```
    
  } else {
    
    ```
    forecast_originale <- res %>%
      select(Giorno, actual, Mu) %>%
      left_join(dati_prezzo, by = "Giorno") %>%
      transmute(
        Giorno,
        Prezzo_reale = Prezzo,
        Modello = nome_modello,
        Prezzo_forecast = Prezzo_lag + Mu
      )
    ```
    
  }
  
  forecast_originale
}

crea_forecast_originale_paese <- function(dataset,
                                          xreg_cols,
                                          arimax_list,
                                          arima_raw_list,
                                          garch_list,
                                          ets_list,
                                          nome_paese) {
  
  map_dfr(0:23, function(i) {
    
    ```
    ts_i <- tsMakingfpp3(
      dataset = dataset,
      ora = i,
      xreg_cols = xreg_cols
    )
    
    bind_rows(
      estrai_forecast_originale(
        model_obj = arimax_list[[i + 1]],
        data_ts = ts_i,
        nome_modello = "ARIMAX"
      ),
      estrai_forecast_originale(
        model_obj = arima_raw_list[[i + 1]],
        data_ts = ts_i,
        nome_modello = "ARIMA_raw"
      ),
      estrai_forecast_originale(
        model_obj = garch_list[[i + 1]],
        data_ts = ts_i,
        nome_modello = "GARCH"
      ),
      estrai_forecast_originale(
        model_obj = ets_list[[i + 1]],
        data_ts = ts_i,
        nome_modello = "ETS"
      )
    ) %>%
      mutate(
        Paese = nome_paese,
        Ora = i
      )
    ```
    
  })
}

forecast_originale_long <- bind_rows(
  crea_forecast_originale_paese(
    dataset = dfItalia,
    xreg_cols = xreg_italia,
    arimax_list = itArima,
    arima_raw_list = itArimaRaw,
    garch_list = itGarch,
    ets_list = itEts,
    nome_paese = "Italia"
  ),
  crea_forecast_originale_paese(
    dataset = dfFrancia,
    xreg_cols = xreg_francia,
    arimax_list = frArima,
    arima_raw_list = frArimaRaw,
    garch_list = frGarch,
    ets_list = frEts,
    nome_paese = "Francia"
  ),
  crea_forecast_originale_paese(
    dataset = dfGermania,
    xreg_cols = xreg_germania,
    arimax_list = geArima,
    arima_raw_list = geArimaRaw,
    garch_list = geGarch,
    ets_list = geEts,
    nome_paese = "Germania"
  ),
  crea_forecast_originale_paese(
    dataset = dfDanimarca,
    xreg_cols = xreg_danimarca,
    arimax_list = deArima,
    arima_raw_list = deArimaRaw,
    garch_list = deGarch,
    ets_list = deEts,
    nome_paese = "Danimarca"
  )
)

forecast_originale_table <- forecast_originale_long %>%
  select(
    Paese,
    Ora,
    Giorno,
    Prezzo_reale,
    Modello,
    Prezzo_forecast
  ) %>%
  pivot_wider(
    names_from = Modello,
    values_from = Prezzo_forecast
  ) %>%
  arrange(
    Paese,
    Giorno,
    Ora
  )

forecast_originale_table

write_csv(
  forecast_originale_table,
  "forecast_modelli_prezzo_after_crisis_testFromJanuray.csv"
)

calcola_mae_modello <- function(model_obj) {
  
  if (is.null(model_obj)) {
    return(NA_real_)
  }
  
  if (is.null(model_obj$results)) {
    return(NA_real_)
  }
  
  model_obj$results %>%
    as_tibble() %>%
    summarise(
      MAE = mean(abs(actual - Mu), na.rm = TRUE)
    ) %>%
    pull(MAE)
}

crea_mae_paese <- function(arima_list, arima_raw_list, garch_list, ets_list, nome_paese) {
  
  tibble(
    Ora = 0:23,
    Paese = nome_paese,
    ARIMAX = map_dbl(arima_list, calcola_mae_modello),
    ARIMA_raw = map_dbl(arima_raw_list, calcola_mae_modello),
    GARCH = map_dbl(garch_list, calcola_mae_modello),
    ETS = map_dbl(ets_list, calcola_mae_modello)
  )
}

mae_long <- bind_rows(
  crea_mae_paese(itArima, itArimaRaw, itGarch, itEts, "Italia"),
  crea_mae_paese(frArima, frArimaRaw, frGarch, frEts, "Francia"),
  crea_mae_paese(geArima, geArimaRaw, geGarch, geEts, "Germania"),
  crea_mae_paese(deArima, deArimaRaw, deGarch, deEts, "Danimarca")
)

mae_ore_table <- mae_long %>%
  pivot_longer(
    cols = c(ARIMAX, ARIMA_raw, GARCH, ETS),
    names_to = "Modello",
    values_to = "MAE"
  ) %>%
  mutate(
    Paese_Modello = paste(Paese, Modello, sep = "_")
  ) %>%
  select(Ora, Paese_Modello, MAE) %>%
  pivot_wider(
    names_from = Paese_Modello,
    values_from = MAE
  ) %>%
  mutate(
    across(where(is.numeric), ~ round(.x, 4))
  )

kable(
  mae_ore_table,
  caption = "MAE per ora, Paese e modello"
)

mae_medio_table <- mae_long %>%
  group_by(Paese) %>%
  summarise(
    ARIMAX = mean(ARIMAX, na.rm = TRUE),
    ARIMA_raw = mean(ARIMA_raw, na.rm = TRUE),
    GARCH = mean(GARCH, na.rm = TRUE),
    ETS = mean(ETS, na.rm = TRUE),
    .groups = "drop"
  ) %>%
  mutate(
    across(where(is.numeric), ~ round(.x, 4))
  )

kable(
  mae_medio_table,
  caption = "MAE medio per Paese e modello"
)

plot_forecast_originale <- function(tabella, paese_scelto, ora_scelta) {
  
  plot_df <- tabella %>%
    mutate(Giorno = as_date(Giorno)) %>%
    filter(
      Paese == paese_scelto,
      Ora == ora_scelta
    ) %>%
    arrange(Giorno) %>%
    pivot_longer(
      cols = c(Prezzo_reale, ARIMAX),#, ARIMA_raw, GARCH, ETS),
      names_to = "Serie",
      values_to = "Valore"
    )
  
  ggplot(plot_df, aes(x = Giorno, y = Valore, color = Serie)) +
    geom_line(linewidth = 0.6) +
    labs(
      title = paste("Real price vs forecast -", paese_scelto, "- hour", ora_scelta),
      x = "Day",
      y = "Price",
      color = "Serie"
    ) +
    theme_minimal()
}

plot_forecast_originale(
  tabella = forecast_originale_table,
  paese_scelto = "Italia",
  ora_scelta = 23
)

for (i in 0:23) {
  
  print(
    plot_forecast_originale(
      tabella = forecast_originale_table,
      paese_scelto = "Italia",
      ora_scelta = i
    )
  )
}

plot_forecast_originale <- function(tabella, paese_scelto, date_breaks = "1 day") {
  first_day <- "2024-09-14"
  last_day <- "2024-09-28"
  
  plot_df <- tabella %>%
    mutate(
      Giorno = as_date(Giorno),
      Ora = as.integer(Ora),
      giorno_num = wday(Giorno, week_start = 1),
      DateTime = as.POSIXct(
        paste(Giorno, sprintf("%02d:00:00", Ora)),
        format = "%Y-%m-%d %H:%M:%S",
        tz = "UTC",
      )
    ) %>%
    filter(
      Paese == paese_scelto, Giorno >= first_day, Giorno <= last_day#, giorno_num <= 5
    ) %>%
    arrange(DateTime) %>%
    pivot_longer(
      cols = c(Prezzo_reale, ARIMAX),#, ARIMA_raw, GARCH, ETS),
      names_to = "Serie",
      values_to = "Valore"
    )
  
  ggplot(plot_df, aes(x = DateTime, y = Valore, color = Serie)) +
    geom_line(linewidth = 0.5, na.rm = TRUE) +
    scale_x_datetime(
      date_breaks = date_breaks,
      date_labels = "%d %b"
    ) +
    labs(
      title = paste("Real Price vs forecast - 2024 -", paese_scelto),
      x = "Date",
      y = "Price",
      color = "Serie"
    ) +
    theme_minimal() +
    theme(
      axis.text.x = element_text(angle = 45, hjust = 1)
    )
}

plot_forecast_originale(
  tabella = forecast_originale_table,
  paese_scelto = "Italia"
)

calcola_mae_modello_weekdays <- function(model_obj) {
  
  if (is.null(model_obj)) {
    return(NA_real_)
  }
  
  if (is.null(model_obj$results)) {
    return(NA_real_)
  }
  
  model_obj$results %>%
    as_tibble() %>%
    mutate(
      Giorno = as_date(Giorno),
      giorno_num = wday(Giorno, week_start = 1)
    ) %>%
    filter(
      giorno_num <= 5
    ) %>%
    summarise(
      MAE = mean(abs(actual - Mu), na.rm = TRUE)
    ) %>%
    pull(MAE)
}

crea_mae_paese_weekdays <- function(arima_list, arima_raw_list, garch_list, ets_list, nome_paese) {
  
  tibble(
    Ora = 0:23,
    Paese = nome_paese,
    ARIMAX = map_dbl(arima_list, calcola_mae_modello_weekdays),
    ARIMA_raw = map_dbl(arima_raw_list, calcola_mae_modello_weekdays),
    GARCH = map_dbl(garch_list, calcola_mae_modello_weekdays),
    ETS = map_dbl(ets_list, calcola_mae_modello_weekdays)
  )
}

mae_long_weekdays <- bind_rows(
  crea_mae_paese_weekdays(itArima, itArimaRaw, itGarch, itEts, "Italia"),
  crea_mae_paese_weekdays(frArima, frArimaRaw, frGarch, frEts, "Francia"),
  crea_mae_paese_weekdays(geArima, geArimaRaw, geGarch, geEts, "Germania"),
  crea_mae_paese_weekdays(deArima, deArimaRaw, deGarch, deEts, "Danimarca")
)

mae_ore_weekdays_table <- mae_long_weekdays %>%
  pivot_longer(
    cols = c(ARIMAX, ARIMA_raw, GARCH, ETS),
    names_to = "Modello",
    values_to = "MAE"
  ) %>%
  mutate(
    Paese_Modello = paste(Paese, Modello, sep = "_")
  ) %>%
  select(Ora, Paese_Modello, MAE) %>%
  pivot_wider(
    names_from = Paese_Modello,
    values_from = MAE
  ) %>%
  mutate(
    across(where(is.numeric), ~ round(.x, 4))
  )

kable(
  mae_ore_weekdays_table,
  caption = "MAE per ora, Paese e modello, solo giorni feriali"
)

mae_medio_weekdays_table <- mae_long_weekdays %>%
  group_by(Paese) %>%
  summarise(
    ARIMAX = mean(ARIMAX, na.rm = TRUE),
    ARIMA_raw = mean(ARIMA_raw, na.rm = TRUE),
    GARCH = mean(GARCH, na.rm = TRUE),
    ETS = mean(ETS, na.rm = TRUE),
    .groups = "drop"
  ) %>%
  mutate(
    across(where(is.numeric), ~ round(.x, 4))
  )

kable(
  mae_medio_weekdays_table,
  caption = "MAE medio per Paese e modello, solo giorni feriali"
)

plot_mae_paese <- function(tabella, paese_scelto) {
  
  colonne_paese <- names(tabella)[str_starts(names(tabella), paste0(paese_scelto, "_"))]
  
  if (length(colonne_paese) == 0) {
    stop("Paese non trovato. Usa uno tra: Italia, Francia, Germania, Danimarca")
  }
  
  plot_df <- tabella %>%
    select(Ora, all_of(colonne_paese)) %>%
    pivot_longer(
      cols = all_of(colonne_paese),
      names_to = "Modello",
      values_to = "MAE"
    ) %>%
    mutate(
      Modello = str_remove(Modello, paste0("^", paese_scelto, "_"))
    )
  
  ggplot(plot_df, aes(x = Ora, y = MAE, color = Modello)) +
    geom_line(linewidth = 1) +
    geom_point(size = 2) +
    scale_x_continuous(
      breaks = 0:23
    ) +
    labs(
      title = paste("MAE for each hour -", paese_scelto),
      x = "Hour",
      y = "MAE",
      color = "Model"
    ) +
    theme_minimal()
}

plot_mae_paese(mae_ore_table, "Italia")
plot_mae_paese(mae_ore_table, "Francia")
plot_mae_paese(mae_ore_table, "Germania")
plot_mae_paese(mae_ore_table, "Danimarca")

ts_once <- tsMakingfpp3(
  dataset = dfItalia,
  ora = 11,
  xreg_cols = xreg_italia
)

tic()
arima_once <- arimaCV(
  data_ts = ts_once,
  xreg_cols = xreg_italia
)
toc()

arima_once$results %>%
  as_tibble() %>%
  summarise(
    MAE = mean(abs(actual - Mu), na.rm = TRUE)
  ) %>%
  pull(MAE)

plot_prezzi_nazioni <- function(start_date, end_date) {
  
  start_date <- as.POSIXct(start_date, tz = "UTC")
  
  if (str_detect(end_date, "^\d{4}-\d{2}-\d{2}$")) {
    end_date <- as.POSIXct(paste(end_date, "23:59:59"), tz = "UTC")
  } else {
    end_date <- as.POSIXct(end_date, tz = "UTC")
  }
  
  prezzi_long <- bind_rows(
    dfItalia %>%
      as_tibble() %>%
      select(Data, Prezzo) %>%
      mutate(Paese = "Italia"),
    
    ```
    dfFrancia %>%
      as_tibble() %>%
      select(Data, Prezzo) %>%
      mutate(Paese = "Francia"),
    
    dfGermania %>%
      as_tibble() %>%
      select(Data, Prezzo) %>%
      mutate(Paese = "Germania"),
    
    dfDanimarca %>%
      as_tibble() %>%
      select(Data, Prezzo) %>%
      mutate(Paese = "Danimarca")
    ```
    
  ) %>%
    filter(Data >= start_date, Data <= end_date)
  
  ggplot(prezzi_long, aes(x = Data, y = Prezzo, color = Paese)) +
    geom_line(linewidth = 0.6, alpha = 0.8) +
    labs(
      title = "Prices",
      subtitle = paste("Period:", as.Date(start_date), "-", as.Date(end_date)),
      x = "Date",
      y = "Price [EUR/MWh]",
      color = "Country"
    ) +
    theme_minimal()
}

plot_prezzi_nazioni(
  start_date = "2024-01-01",
  end_date = "2024-01-31"
)

plot_prezzi_nazioni_daily <- function(start_date, end_date) {
  
  start_date <- as.Date(start_date)
  end_date <- as.Date(end_date)
  
  prezzi_long <- bind_rows(
    dfItalia %>%
      as_tibble() %>%
      select(Data, Prezzo) %>%
      mutate(Paese = "Italia"),
    
    ```
    dfFrancia %>%
      as_tibble() %>%
      select(Data, Prezzo) %>%
      mutate(Paese = "Francia"),
    
    dfGermania %>%
      as_tibble() %>%
      select(Data, Prezzo) %>%
      mutate(Paese = "Germania"),
    
    dfDanimarca %>%
      as_tibble() %>%
      select(Data, Prezzo) %>%
      mutate(Paese = "Danimarca")
    ```
    
  ) %>%
    mutate(Giorno = as.Date(Data)) %>%
    filter(Giorno >= start_date, Giorno <= end_date) %>%
    group_by(Paese, Giorno) %>%
    summarise(
      Prezzo_medio = mean(Prezzo, na.rm = TRUE),
      .groups = "drop"
    )
  
  ggplot(prezzi_long, aes(x = Giorno, y = Prezzo_medio, color = Paese)) +
    geom_line(linewidth = 0.8) +
    labs(
      title = "Avg daily prices",
      subtitle = paste("Period:", start_date, "-", end_date),
      x = "Date",
      y = "Avg daily price [EUR/MWh]",
      color = "Country"
    ) +
    theme_minimal()
}

plot_prezzi_nazioni_daily(
  start_date = "2019-01-01",
  end_date = "2024-12-31"
)
