# club_assignment_stv_hours_auto_v8_final_output.R

library(dplyr)
library(readr)
library(tidyr)
library(stringr)

# --- Ρυθμίσεις ---
required_hours <- 10L
responses_file <- "responses.csv" 
clubs_file <- "clubs.csv"
output_prefix_assignments <- "club_assignments"
auto_select_count <- 15L 
min_pool_size <- 15L 
set.seed(42)

# --- Διαβάζουμε δεδομένα ---
responses <- read_csv(responses_file, show_col_types = FALSE)
clubs <- read_csv(clubs_file, show_col_types = FALSE)

# --- Καθαρισμός και εναρμόνιση Clubs ---
colnames(clubs) <- tolower(trimws(colnames(clubs)))
club_name_source <- if("club_name" %in% colnames(clubs)) "club_name" else "club_id"
if("clubname" %in% colnames(clubs) & !("club_name" %in% colnames(clubs))) {
  club_name_source <- "clubname"
}

if("hours_per_week" %in% colnames(clubs)) {
  clubs <- clubs |> rename(hours = hours_per_week)
} else if(!("hours" %in% colnames(clubs))) {
  hours_col_name <- setdiff(colnames(clubs), c("club_id", "club_name", "clubname"))[1]
  if (!is.na(hours_col_name)) {
    clubs <- clubs |> rename(hours = hours_col_name)
  }
}

clubs <- clubs |>
  mutate(
    club_id = trimws(tolower(club_id)),
    club_name = .data[[club_name_source]], 
    club_name = trimws(club_name),
    hours = as.integer(hours),
    hours = if_else(is.na(hours), 2L, hours) 
  ) |>
  select(club_id, club_name, hours)

# --- Καθαρισμός και εναρμόνιση Responses ---
student_col <- colnames(responses)[1]
responses <- responses |>
  mutate(across(all_of(student_col), as.character)) 

initial_club_cols <- trimws(tolower(colnames(responses)[-1]))
colnames(responses) <- c(student_col, initial_club_cols)

responses_long_master <- responses |>
  pivot_longer(cols = -all_of(student_col),
               names_to = "ClubID", values_to = "Rank") |>
  mutate(
    ClubID = trimws(tolower(ClubID)),
    Rank = as.integer(Rank)
  ) |>
  filter(!is.na(Rank))

# --- Ενεργές Καταστάσεις ---
active_clubs <- initial_club_cols
student_hours <- data.frame(StudentID = unique(responses[[student_col]]),
                            HoursAssigned = 0L,
                            stringsAsFactors = FALSE)
colnames(student_hours)[1] <- student_col
club_assignments <- data.frame(StudentID = character(), ClubID = character(), ClubName = character(), stringsAsFactors = FALSE)
colnames(club_assignments)[1] <- student_col
round <- 1L

cat(sprintf("--- Έναρξη Διαδικασίας Κατανομής Ομίλων (Στόχος: %d Ώρες/Μαθητή, Min Pool: %d) ---\n", required_hours, min_pool_size))

repeat {
  # --- 1. Υπολογισμός Πρώτων Προτιμήσεων (Τρέχουσα κατάσταση) ---
  
  active_students <- student_hours |>
    filter(HoursAssigned < required_hours) |>
    pull(all_of(student_col))
  
  current_prefs <- responses_long_master |>
    filter(ClubID %in% active_clubs) |>
    filter(get(student_col) %in% active_students) |>
    group_by(across(all_of(student_col))) |>
    filter(Rank == min(Rank, na.rm = TRUE)) |> 
    ungroup()
  
  counts <- current_prefs |>
    count(ClubID, name = "FirstPrefCount") |>
    right_join(data.frame(ClubID = active_clubs), by = "ClubID") |>
    replace_na(list(FirstPrefCount = 0))
  
  cat(sprintf("\n*** Γύρος %d ***\n", round))
  
  # Έλεγχος Τερματισμού
  if(length(active_clubs) == 0 || length(active_students) == 0) {
    students_not_reached_target <- student_hours |>
      filter(HoursAssigned < required_hours)
    
    if(length(active_clubs) == 0 && nrow(students_not_reached_target) > 0) {
      cat(sprintf("\nΤΕΡΜΑΤΙΣΜΟΣ ΛΟΓΩ ΕΞΑΝΤΛΗΣΗΣ ΟΜΙΛΩΝ: %d μαθητές δεν συμπλήρωσαν τις %d ώρες.\n", 
                  nrow(students_not_reached_target), required_hours))
    } else {
      cat("\nΤερματισμός: Όλοι οι μαθητές έχουν συμπληρώσει τις ώρες τους.\n")
    }
    break
  }
  
  # --- 2. Εντοπισμός Δημοφιλέστερου Ομίλου ---
  max_count <- max(counts$FirstPrefCount)
  if (max_count == 0) {
    cat("Δεν υπάρχουν πλέον πρώτες προτιμήσεις για ενεργούς Ομίλους. Τερματισμός.\n")
    break
  }
  
  pop_candidates <- counts |> filter(FirstPrefCount == max_count)
  club_to_select <- sort(pop_candidates$ClubID)[1]
  
  match_idx <- match(club_to_select, clubs$club_id)
  club_name <- clubs$club_name[match_idx]
  club_hours <- clubs$hours[match_idx] 
  
  cat(sprintf("-> Δημοφιλέστερος Όμιλος: %s (%s) με %d **πρώτες** προτιμήσεις (Ώρες: %d).\n",
              club_to_select, club_name, max_count, club_hours))
  
  # --- 3. Διεύρυνση Pool Υποψηφίων (ΛΟΓΙΚΗ ΕΛΑΧΙΣΤΟΥ 15) ---
  
  students_for_club_pool <- current_prefs |>
    filter(ClubID == club_to_select) |>
    pull(all_of(student_col))
  
  if(length(students_for_club_pool) < min_pool_size) {
    cat(sprintf("-> Οι πρώτες προτιμήσεις (%d) είναι < %d. Αναζήτηση σε χαμηλότερα ranks...\n", 
                length(students_for_club_pool), min_pool_size))
    
    club_rankings <- responses_long_master |>
      filter(ClubID == club_to_select) |>
      filter(get(student_col) %in% active_students) |>
      arrange(Rank) |>
      select(all_of(student_col), Rank)
    
    max_rank_to_include <- club_rankings$Rank[min(nrow(club_rankings), min_pool_size)]
    
    students_for_club_pool <- club_rankings |>
      filter(Rank <= max_rank_to_include) |>
      pull(all_of(student_col))
    
    cat(sprintf("-> Το pool διευρύνθηκε για να συμπεριλάβει μαθητές μέχρι την %dη προτίμηση (Συνολικά: %d υποψήφιοι).\n", 
                max_rank_to_include, length(students_for_club_pool)))
  }
  
  # --- 4. Αυτόματη Επιλογή 15 Μαθητών (Προσομοίωση) ---
  
  if (length(students_for_club_pool) > 0) {
    num_to_select <- min(auto_select_count, length(students_for_club_pool))
    final_selected_students <- sample(students_for_club_pool, size = num_to_select, replace = FALSE)
    
    cat(sprintf("-> Επιλέγονται τυχαία %d μαθητές από το pool.\n", num_to_select))
  } else {
    final_selected_students <- character(0)
  }
  
  
  # --- 5. Καταχώρηση και Μεταφορά Ψήφων ---
  
  if(length(final_selected_students) > 0) {
    new_assignments <- data.frame(StudentID = final_selected_students,
                                  ClubID = club_to_select,
                                  ClubName = club_name,
                                  stringsAsFactors = FALSE)
    colnames(new_assignments)[1] <- student_col
    club_assignments <- bind_rows(club_assignments, new_assignments)
    
    for (sid in final_selected_students) {
      student_hours[student_hours[[student_col]] == sid, "HoursAssigned"] <- 
        student_hours[student_hours[[student_col]] == sid, "HoursAssigned"] + club_hours
    }
    
    cat(sprintf("-> Καταχωρήθηκαν %d μαθητές στον Όμιλο %s.\n", length(final_selected_students), club_name))
    
    assignment_file <- sprintf("%s_%s.csv", output_prefix_assignments, club_to_select)
    write_csv(new_assignments, assignment_file)
  }
  
  # Αφαίρεση του Ομίλου από τη λίστα των ενεργών (Βάσει του Κανόνα του Χρήστη)
  active_clubs <- setdiff(active_clubs, club_to_select)
  
  # --- 6. Ενημέρωση Ranks (Μεταφορά Ψήφων) ---
  
  responses_long_master <- responses_long_master |>
    mutate(Rank = ifelse(ClubID == club_to_select, NA_integer_, Rank)) |>
    filter(!is.na(Rank))
  
  responses_long_master <- responses_long_master |>
    group_by(across(all_of(student_col))) |>
    mutate(Rank = rank(Rank, ties.method = "min")) |> 
    ungroup()
  
  # --- 7. Αποθήκευση Ενδιάμεσων Αρχείων ---
  write_csv(student_hours, "student_hours_log.csv")
  
  round <- round + 1L
}

# --- Τελική Καταγραφή & Νέο Αρχείο (Student Club List) ---
cat("\nΟλοκληρώθηκε η διαδικασία κατανομής.\n")
write_csv(club_assignments, "club_assignments_final.csv")


# --- ΒΗΜΑ 8: ΔΗΜΙΟΥΡΓΙΑ ΑΡΧΕΙΟΥ ΜΕ ΛΙΣΤΑ ΟΜΙΛΩΝ ΑΝΑ ΜΑΘΗΤΗ ---

student_club_list <- club_assignments |>
  # Ομαδοποίηση ανά μαθητή
  group_by(across(all_of(student_col))) |>
  # Συνένωση των ClubName σε μία συμβολοσειρά, χωρισμένη με κόμμα
  summarise(
    Clubs_Assigned = paste(ClubName, collapse = ", "),
    .groups = 'drop'
  )

# Ενσωμάτωση των συνολικών ωρών για πληρέστερη εικόνα
student_club_list <- student_club_list |>
  left_join(student_hours, by = student_col) |>
  select(all_of(student_col), Clubs_Assigned, HoursAssigned)

# Αποθήκευση του νέου αρχείου
write_csv(student_club_list, "student_club_list.csv")
cat("Δημιουργήθηκε το αρχείο: student_club_list.csv (Λίστα Ομίλων ανά Μαθητή)\n")

# --- ΒΗΜΑ 9: ΕΥΡΕΣΗ ΟΜΙΛΩΝ ΜΕ ΛΙΓΟΤΕΡΟΥΣ ΑΠΟ 10 ΜΑΘΗΤΕΣ ---

# Υπολογίζουμε τους μαθητές ανά Όμιλο
clubs_less_than_10 <- club_assignments |>
  # Ομαδοποίηση ανά όνομα Ομίλου
  group_by(ClubName) |>
  # Καταμέτρηση των αναθέσεων (μαθητών)
  summarise(
    Students_Count = n(),
    .groups = 'drop'
  ) |>
  # Φιλτράρισμα μόνο για όσους έχουν λιγότερους από 10 μαθητές
  filter(Students_Count < 10) |>
  # Ταξινόμηση για ευκολότερη επισκόπηση
  arrange(Students_Count, ClubName)

# Εκτύπωση αποτελεσμάτων στην κονσόλα
cat("\n\n--- ΟΜΙΛΟΙ ΜΕ ΛΙΓΟΤΕΡΟΥΣ ΑΠΟ 10 ΜΑΘΗΤΕΣ ---\n")
print(clubs_less_than_10)

# Αποθήκευση του αποτελέσματος σε αρχείο CSV
write_csv(clubs_less_than_10, "clubs_less_than_10_students.csv")
cat("\nΑποθηκεύτηκαν τα αποτελέσματα στο: clubs_less_than_10_students.csv\n")