#setup ----
library(tidyverse)
library(influxdbclient)
library(rmarkdown)

if(Sys.info()[4] == "pseudotsuga") {
  setwd("~/Documents/dataProjects/laundry_status")
} else {
  setwd("/laundry_status")
}
Sys.setenv(TZ='America/Chicago')
# parameters needed to make connection to Database
token <- substr(read_file("data/api_key"), 1, 88)
org = "home_assistant"
bucket = "home_assistant"
## make connection to the influxDB bucket
home_assistant <- InfluxDBClient$new(url = "https://influxdb.dendroalsia.net",
                                     token = token,
                                     org = org)
update_interval <- 5
cronjob_interval <- 60
power_threshold_on <- 10
power_threshold_wash_door <- 4
power_threshold_dry_door <- 1.5

# ---- set variables
entities <- data.frame(name = c("washing machine", "dryer"), entity_id = c("washing_machine_power", "dryer_power"))

colors <- data.frame(value = c("off", "on"), color = c("#bcbcbc", "#008080"))

# Define a function to calculate the time difference
calculateTimeAgo <- function(eventTime) {
  current <- Sys.time()  # Get the current time
  timeDiff <- as.duration(current - eventTime)  # Calculate the time difference
  
  # Convert the time difference to appropriate units and format the result
  if (timeDiff >= hours(24)) {
    result <- paste(round(timeDiff / dhours(24)), "days ago")
  } else if (timeDiff >= hours(1)) {
    result <- paste(round(timeDiff / dhours(1)), "hours ago")
  } else if (timeDiff >= minutes(1)) {
    result <- paste(round(timeDiff / dminutes(1)), "minutes ago")
  } else {
    result <- "Just now"
  }
  
  return(result)
}

# ---- update_data function
update_data <- function(){
  
  run_time <- Sys.time()
  values <- home_assistant$query('from(bucket: "home_assistant") |> range(start: -7d) |> filter(fn: (r) => r["entity_id"] == "washing_machine_power" or r["entity_id"] == "dryer_power") |> filter(fn: (r) => r["_field"] == "value") |> filter(fn: (r) => r["_measurement"] == "W")',
                                 POSIXctCol = NULL)
  values <- bind_rows(values)
  values <- values %>%
    rename(value = "_value",
           time = "_time")
  values <- values %>%
    mutate(
      time = as.POSIXct(time, tz = "America/Chicago"),
      status = ifelse(value > power_threshold_on, "on", "off")) %>%
    mutate(door_threshold = ifelse(entity_id == "washing_machine_power", power_threshold_wash_door, power_threshold_dry_door)) %>%
    mutate(door = ifelse(value < door_threshold, "open", "closed"))
  
  values_by_entity <- as.list(NULL)
  for(entity in entities$entity_id) {
    values_by_entity[[entity]] <- values %>%
      filter(entity_id %in% entity) %>%
      mutate(end_time = c(time[-1], run_time))
  }
  values <- bind_rows(values_by_entity)
  
  last_change <- values %>% 
    group_by(entity_id, status) %>% 
    slice_max(n = 1, order_by = time) %>% 
    pivot_wider(id_cols = domain, names_from = c(entity_id, status), values_from = time)
  
  status_door <- values %>% 
    group_by(entity_id) %>% 
    slice_max(n = 1, order_by = time) %>% 
    select(entity_id, door) %>%
    pivot_wider(names_from = entity_id, values_from = door)
  
  current_status <- as.list(NULL)
  for (entity in entities$entity_id){
    current_status[[entity]] <- ifelse(values %>% filter(entity_id %in% entity) %>% tail(1) %>% pull(value) > power_threshold_on, "on", "off")
  }
  
# ---- make plots
  plot_1day <- ggplot(data = values %>% filter(time >= max(values$end_time) - hours(24))) +
    geom_tile(aes(x = time + seconds(round(as.numeric(difftime(end_time, time, unit = "secs")))/2),
                  y = entity_id,
                  width = seconds(round(as.numeric(difftime(end_time, time, unit = "secs")))),
                  height = 0.5,
                  fill = status)) +
    scale_y_discrete(breaks = entities$entity_id, labels = entities$name) +
    scale_x_datetime(breaks = seq(round_date(max(values$end_time), "4 hours") - hours(24), round_date(max(values$end_time), "4 hours"), by = "4 hours"), date_labels = '%I:%M %p', date_minor_breaks = "1 hours") +
    scale_fill_manual(values = colors$color) +
    theme(axis.text.x = element_text(angle = 30, vjust = 0.5)) +
    labs(title = "Last 24 hours",
         x = NULL,
         y = NULL,
         fill = NULL)
  
  plot_1week <- ggplot(data = values) +
    geom_tile(aes(x = time + seconds(round(as.numeric(difftime(end_time, time, unit = "secs")))/2),
                  y = entity_id,
                  width = seconds(round(as.numeric(difftime(end_time, time, unit = "secs")))),
                  height = 0.5,
                  fill = status)) +
    scale_y_discrete(breaks = entities$entity_id, labels = entities$name) +
    scale_x_datetime(date_breaks = "1 day", date_labels = '%A', date_minor_breaks = "4 hours") +
    scale_fill_manual(values = colors$color) +
    theme(axis.text.x = element_text(angle = 30, vjust = 0.5)) +
    labs(title = "The past week",
         x = NULL,
         y = NULL,
         fill = NULL)
  
  plot_1week_days <- ggplot(data = values %>% 
                              filter(as.Date(time, tz = "America/Chicago") == as.Date(end_time, tz = "America/Chicago")) %>%
                              mutate(date = as.Date(time, tz = "America/Chicago")) %>%
                              left_join(. , entities, by = join_by(entity_id)) %>%
                              mutate(name = factor(name, levels = c("washing machine", "dryer")))) +
    geom_rect(aes(xmin = date - hours(8),
                  xmax = date + hours(8),
                  ymin = ymd_hms(paste("2023-01-01", strftime(time, format = "%H:%M:%S"))),
                  ymax = ymd_hms(paste("2023-01-01", strftime(end_time, format = "%H:%M:%S"))),
                  fill = status)) +
    facet_grid(name ~ .) +
    scale_y_datetime(date_breaks = "4 hours", date_labels = '%I:%M %p',  minor_breaks = "2 hours", expand = expansion(mult = 0)) +
    scale_x_datetime(date_breaks = "1 day", date_labels = '%A', minor_breaks = NULL) +
    scale_fill_manual(values = colors$color) +
    theme(axis.text.x = element_text(angle = 30, vjust = 0.5)) +
    labs(title = "The past week",
         x = "Day",
         y = "Time of Day",
         fill = NULL)
  
  # ---- generate html
  render("laundry_status.Rmd",
         output_dir = "html",
         output_file = "index.html")
  
}

# for(i in 1:(cronjob_interval/update_interval)){
#   message(Sys.time())
#   update_data()
#   Sys.sleep(60*update_interval)
# }

continue <- TRUE
while(continue){
  message(Sys.time())
  update_data()
  Sys.sleep(60*update_interval)
}