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

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) {
  dataset %>%
    as_tibble() %>%
    filter(Ora_ == ora) %>%
    arrange(Giorno) %>%
    mutate(
      diffPrezzo = Prezzo - lag(Prezzo)
    ) %>%
    filter(!is.na(diffPrezzo)) %>%
    select(-Data) %>%
    as_tsibble(index = Giorno)
}

garchCV <- function(data_ts) {
  target_col = "diffPrezzo"
  start_date = "2020-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
    )
  )
}

arimaCV <- function(data_ts) {
  
  target_col <- "diffPrezzo"
  start_date <- "2020-01-01"
  refit_every <- 90
  
  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(
      arima = 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
    )
  )
}

etsCV <- function(data_ts) {
  
  target_col <- "diffPrezzo"
  start_date <- "2020-01-01"
  refit_every <- 90
  
  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
    )
  )
}

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)
  )

dfFrancia <- dfFrancia %>%
  mutate(
    Giorno = date(Data),
    Ora_ = hour(Data)
  )

dfGermania <- dfGermania %>%
  mutate(
    Giorno = date(Data),
    Ora_ = hour(Data)
  )

dfDanimarca <- dfDanimarca %>%
  mutate(
    Giorno = date(Data),
    Ora_ = hour(Data)
  )

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

itGarch <- list()
frGarch <- list()
geGarch <- list()
deGarch <- list()

for (i in 0:23) {
  dataset <- tsMaking(dfItalia, i)
  itGarch[[i + 1]] <- garchCV(dataset)
}

for (i in 0:23) {
  dataset <- tsMaking(dfFrancia, i)
  frGarch[[i + 1]] <- garchCV(dataset)
}

for (i in 0:23) {
  dataset <- tsMaking(dfGermania, i)
  geGarch[[i + 1]] <- garchCV(dataset)
}

for (i in 0:23) {
  dataset <- tsMaking(dfDanimarca, i)
  deGarch[[i + 1]] <- garchCV(dataset)
}

itArima <- list()
frArima <- list()
geArima <- list()
deArima <- list()

for (i in 0:23) {
  dataset <- tsMakingfpp3(dfItalia, i)
  itArima[[i + 1]] <- arimaCV(dataset)
}

for (i in 0:23) {
  dataset <- tsMakingfpp3(dfFrancia, i)
  frArima[[i + 1]] <- arimaCV(dataset)
}

for (i in 0:23) {
  dataset <- tsMakingfpp3(dfGermania, i)
  geArima[[i + 1]] <- arimaCV(dataset)
}

for (i in 0:23) {
  dataset <- tsMakingfpp3(dfDanimarca, i)
  deArima[[i + 1]] <- arimaCV(dataset)
}

itEts <- list()
frEts <- list()
geEts <- list()
deEts <- list()

for (i in 0:23) {
  dataset <- tsMakingfpp3(dfItalia, i)
  itEts[[i + 1]] <- etsCV(dataset)
}

for (i in 0:23) {
  dataset <- tsMakingfpp3(dfFrancia, i)
  frEts[[i + 1]] <- etsCV(dataset)
}

for (i in 0:23) {
  dataset <- tsMakingfpp3(dfGermania, i)
  geEts[[i + 1]] <- etsCV(dataset)
}

for (i in 0:23) {
  dataset <- tsMakingfpp3(dfDanimarca, i)
  deEts[[i + 1]] <- etsCV(dataset)
}

mae_table <- tibble(
  Ora_ = 0:23,
  
  Italia_GARCH = map_dbl(1:24, function(i) {
    mean(abs(itGarch[[i]]$results$actual - itGarch[[i]]$results$Mu), na.rm = TRUE)
  }),
  
  Italia_ARIMA = map_dbl(1:24, function(i) {
    mean(abs(itArima[[i]]$results$actual - itArima[[i]]$results$Mu), na.rm = TRUE)
  }),
  
  Italia_ETS = map_dbl(1:24, function(i) {
    mean(abs(itEts[[i]]$results$actual - itEts[[i]]$results$Mu), na.rm = TRUE)
  }),
  
  Francia_GARCH = map_dbl(1:24, function(i) {
    mean(abs(frGarch[[i]]$results$actual - frGarch[[i]]$results$Mu), na.rm = TRUE)
  }),
  
  Francia_ARIMA = map_dbl(1:24, function(i) {
    mean(abs(frArima[[i]]$results$actual - frArima[[i]]$results$Mu), na.rm = TRUE)
  }),
  
  Francia_ETS = map_dbl(1:24, function(i) {
    mean(abs(frEts[[i]]$results$actual - frEts[[i]]$results$Mu), na.rm = TRUE)
  }),
  
  Germania_GARCH = map_dbl(1:24, function(i) {
    mean(abs(geGarch[[i]]$results$actual - geGarch[[i]]$results$Mu), na.rm = TRUE)
  }),
  
  Germania_ARIMA = map_dbl(1:24, function(i) {
    mean(abs(geArima[[i]]$results$actual - geArima[[i]]$results$Mu), na.rm = TRUE)
  }),
  
  Germania_ETS = map_dbl(1:24, function(i) {
    mean(abs(geEts[[i]]$results$actual - geEts[[i]]$results$Mu), na.rm = TRUE)
  }),
  
  Danimarca_GARCH = map_dbl(1:24, function(i) {
    mean(abs(deGarch[[i]]$results$actual - deGarch[[i]]$results$Mu), na.rm = TRUE)
  }),
  
  Danimarca_ARIMA = map_dbl(1:24, function(i) {
    mean(abs(deArima[[i]]$results$actual - deArima[[i]]$results$Mu), na.rm = TRUE)
  }),
  
  Danimarca_ETS = map_dbl(1:24, function(i) {
    mean(abs(deEts[[i]]$results$actual - deEts[[i]]$results$Mu), na.rm = TRUE)
  })
)

mae_table

prezzi_paesi <- 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(
    Anno = year(Data)
  )

anni <- sort(unique(prezzi_paesi$Anno))

for (a in anni) {
  
  p <- prezzi_paesi %>%
    filter(Anno == a) %>%
    ggplot(aes(x = Data, y = Prezzo, color = Paese)) +
    geom_line(alpha = 0.55, linewidth = 0.25) +
    labs(
      title = paste("Hourly electricity price -", a),
      x = "Date",
      y = "Price",
      color = "Country"
    ) +
    theme_minimal()
  
  print(p)
}

prezzi_paesi_daily <- prezzi_paesi %>%
  mutate(
    Giorno = as_date(Data)
  ) %>%
  group_by(Paese, Giorno) %>%
  summarise(
    Prezzo_medio = mean(Prezzo, na.rm = TRUE),
    .groups = "drop"
  ) %>%
  mutate(
    Anno = year(Giorno)
  )

anni_daily <- sort(unique(prezzi_paesi_daily$Anno))

for (a in anni_daily) {
  
  p <- prezzi_paesi_daily %>%
    filter(Anno == a) %>%
    ggplot(aes(x = Giorno, y = Prezzo_medio, color = Paese)) +
    geom_line(linewidth = 0.55, alpha = 0.85) +
    labs(
      title = paste("Average daily electricity price -", a),
      x = "Day",
      y = "Average daily price",
      color = "Country"
    ) +
    theme_minimal()
  
  print(p)
}

prezzi_paesi <- 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")
)

ggplot(prezzi_paesi, aes(x = Data, y = Prezzo, color = Paese)) +
  geom_line(alpha = 0.7, linewidth = 0.4) +
  labs(
    title = "Hourly electricity price",
    x = "Date",
    y = "Price",
    color = "Country"
  ) +
  theme_minimal()

prezzi_paesi_weekly <- prezzi_paesi %>%
  mutate(
    Settimana = floor_date(Data, unit = "week")
  ) %>%
  group_by(Paese, Settimana) %>%
  summarise(
    Prezzo_medio = mean(Prezzo, na.rm = TRUE),
    .groups = "drop"
  )

ggplot(prezzi_paesi_weekly, aes(x = Settimana, y = Prezzo_medio, color = Paese)) +
  geom_line(linewidth = 0.7) +
  labs(
    title = "Average weekly electricity price",
    x = "week",
    y = "Average weekly price",
    color = "Country"
  ) +
  theme_minimal()

mae_ets_long <- mae_table %>%
  select(
    Ora_,
    Italia_ETS,
    Francia_ETS,
    Germania_ETS,
    Danimarca_ETS
  ) %>%
  pivot_longer(
    cols = -Ora_,
    names_to = "Paese",
    values_to = "MAE"
  ) %>%
  mutate(
    Paese = str_remove(Paese, "_ETS")
  )

ggplot(mae_ets_long, aes(x = Ora_, y = MAE, color = Paese)) +
  geom_line(linewidth = 0.8) +
  geom_point(size = 1.8) +
  scale_x_continuous(
    breaks = 0:23
  ) +
  labs(
    title = "MAE ETS model",
    x = "Hour",
    y = "MAE",
    color = "Country"
  ) +
  theme_minimal()
