# Smart City Utilities Operations Simulation

# Set seed for reproducibility so results can be verified
set.seed(42)


# TASK 1A: Generate Production Data

# Define simulation parameters
n_days      <- 30   # 30 days of operation
n_utilities <- 6    # 6 utility services
n_teams     <- 5    # 5 operational teams per utility
base_output <- 40   # BaseOutput constant

# Calculate total number of rows in the dataframe
# (one row per Day-Utility-Team combination)
total_rows <- n_days * n_utilities * n_teams   # 30 * 6 * 5 = 900

# Pre-allocate vectors to hold each column's data
day_col     <- integer(total_rows)
utility_col <- integer(total_rows)
team_col    <- integer(total_rows)
output_col  <- numeric(total_rows)

# Use a single row index to track position in the vectors
row_index <- 1

# Nested loops: iterate over every Day, Utility, and Team combination
for (day in 1:n_days) {
  for (utility in 1:n_utilities) {
    for (team in 1:n_teams) {

      # Generate random noise: integer between -5 and +5 (inclusive)
      random_noise <- sample(-5:5, size = 1)

      # Calculate Output using the given formula:
      # Output = BaseOutput + (UtilityID * TeamID) + RandomNoise
      output_value <- base_output + (utility * team) + random_noise

      # Store values in the pre-allocated vectors at the current row
      day_col[row_index]     <- day
      utility_col[row_index] <- utility
      team_col[row_index]    <- team
      output_col[row_index]  <- output_value

      # Move to the next row
      row_index <- row_index + 1
    }
  }
}

# Assemble the vectors into the required dataframe
production_data <- data.frame(
  Day     = day_col,
  Utility = utility_col,
  Team    = team_col,
  Output  = output_col
)

# Display the first 10 rows as required
cat("=== Task 1A: First 10 rows of production_data ===\n")
print(production_data[1:10, ])
cat("\n")


# TASK 1B: Total Production per Utility

# Pre-allocate a vector to hold total output for each utility
total_output_per_utility <- numeric(n_utilities)

# Loop over each utility and sum all outputs using a nested loop
for (utility in 1:n_utilities) {

  running_total <- 0  # Accumulator for this utility's total

  # Loop through every row in production_data
  for (i in 1:nrow(production_data)) {

    # Check if this row belongs to the current utility
    if (production_data$Utility[i] == utility) {
      running_total <- running_total + production_data$Output[i]
    }
  }

  # Store the total for this utility
  total_output_per_utility[utility] <- running_total
}

# Build the Utility_totals dataframe
Utility_totals <- data.frame(
  Utility     = 1:n_utilities,
  TotalOutput = total_output_per_utility
)

# Display Utility_totals
cat("=== Task 1B: Utility_totals ===\n")
print(Utility_totals)
cat("\n")


# TASK 1C: Detect Production Anomalies

# Pre-allocate the Anomaly column (logical vector)
anomaly_flag <- logical(nrow(production_data))

# For each row, calculate the daily average for its utility,
# then decide if the team's output is anomalous (>10% deviation)
for (i in 1:nrow(production_data)) {

  current_day     <- production_data$Day[i]
  current_utility <- production_data$Utility[i]
  current_output  <- production_data$Output[i]

  # Calculate sum of all team outputs for this utility on this day
  daily_sum   <- 0
  daily_count <- 0

  for (j in 1:nrow(production_data)) {
    if (production_data$Day[j] == current_day &&
        production_data$Utility[j] == current_utility) {
      daily_sum   <- daily_sum + production_data$Output[j]
      daily_count <- daily_count + 1
    }
  }

  # Daily average = sum of all teams / number of teams
  # The spec says "divided by 4" — this uses actual team count for robustness
  daily_avg <- daily_sum / daily_count

  # Mark as anomaly if deviation from average exceeds 10%
  deviation <- abs(current_output - daily_avg) / daily_avg
  anomaly_flag[i] <- deviation > 0.10
}

# Assemble the anomalies dataframe with the Anomaly column
anomalies <- data.frame(
  Day     = production_data$Day,
  Utility = production_data$Utility,
  Team    = production_data$Team,
  Output  = production_data$Output,
  Anomaly = anomaly_flag
)

# Extract rows where Anomaly is TRUE and display the first 10
anomaly_rows <- anomalies[anomalies$Anomaly == TRUE, ]

cat("=== Task 1C: First 10 detected anomalies ===\n")
print(head(anomaly_rows, 10))
cat("\n")


# TASK 1D: Identify Peak Productivity Days

# Pre-allocate vectors for the peak_days dataframe
peak_utility    <- integer(n_utilities)
peak_day        <- integer(n_utilities)
peak_total_out  <- numeric(n_utilities)

# For each utility, find the day with the highest total output
for (utility in 1:n_utilities) {

  best_day        <- NA    # Will hold the day with max total output
  best_total      <- -Inf  # Start with negative infinity so any value beats it

  # Check each day for this utility
  for (day in 1:n_days) {

    # Sum output across all teams for this utility on this day
    day_total <- 0

    for (i in 1:nrow(production_data)) {
      if (production_data$Utility[i] == utility &&
          production_data$Day[i] == day) {
        day_total <- day_total + production_data$Output[i]
      }
    }

    # Update best if this day's total exceeds the current best
    if (day_total > best_total) {
      best_total <- day_total
      best_day   <- day
    }
  }

  # Store results for this utility
  peak_utility[utility]   <- utility
  peak_day[utility]       <- best_day
  peak_total_out[utility] <- best_total
}

# Build the peak_days dataframe
peak_days <- data.frame(
  Utility     = peak_utility,
  Day         = peak_day,
  TotalOutput = peak_total_out
)

# Display peak_days
cat("=== Task 1D: peak_days ===\n")
print(peak_days)
cat("\n")


# TASK 1E: Calculate Efficiency Score

# Pre-allocate the EfficiencyScore column
efficiency_score <- numeric(nrow(production_data))

# Formula: EfficiencyScore = (Output / BaseOutput) * 100
# This expresses each team's output as a percentage of the baseline
for (i in 1:nrow(production_data)) {
  efficiency_score[i] <- (production_data$Output[i] / base_output) * 100
}

# Add the new column to production_data
production_data$EfficiencyScore <- efficiency_score

# Display first 10 rows of the updated dataframe
cat("=== Task 1E: First 10 rows of production_data with EfficiencyScore ===\n")
print(production_data[1:10, ])
cat("\n")