# ============================================================
# Student name: Gaurav Bansod
# Student number: 2519815
# Module code: ACCA7022
# Assessment title: Data Manipulation
# ============================================================

# Reproducible random variation
set.seed(2026)

# ------------------------------------------------------------
# Parameters
# ------------------------------------------------------------
BaseUnits <- 100
ZoneMultiplier <- 8
CategoryMultiplier <- 5
MinVariation <- -12
MaxVariation <- 12
TimePerUnit <- 0.85

number_of_days <- 28
number_of_zones <- 5
number_of_categories <- 6
total_records <- number_of_days * number_of_zones * number_of_categories

UpperThreshold <- 1.15
LowerThreshold <- 0.85

# ------------------------------------------------------------
# A. Generate warehouse data
# ------------------------------------------------------------
warehouse_data <- data.frame(
  Day = integer(total_records),
  Zone = integer(total_records),
  Category = integer(total_records),
  UnitsProcessed = integer(total_records),
  ProcessingTime = numeric(total_records)
)

record_index <- 0

for (day_value in 1:number_of_days) {
  for (zone_value in 1:number_of_zones) {
    for (category_value in 1:number_of_categories) {
      record_index <- record_index + 1
      
      random_variation <- sample(MinVariation:MaxVariation, size = 1)
      units_value <- BaseUnits +
        (zone_value * ZoneMultiplier) +
        (category_value * CategoryMultiplier) +
        random_variation
      processing_time_value <- units_value * TimePerUnit
      
      warehouse_data$Day[record_index] <- day_value
      warehouse_data$Zone[record_index] <- zone_value
      warehouse_data$Category[record_index] <- category_value
      warehouse_data$UnitsProcessed[record_index] <- units_value
      warehouse_data$ProcessingTime[record_index] <- round(processing_time_value, 2)
    }
  }
}

cat("\n============================================================\n")
cat("A. GENERATE WAREHOUSE DATA\n")
cat("============================================================\n")
cat("\nFirst 10 rows of warehouse_data:\n")
print(head(warehouse_data, 10))
cat("Rows in warehouse_data:", nrow(warehouse_data), "\n")
cat("Columns in warehouse_data:", ncol(warehouse_data), "\n")

# ------------------------------------------------------------

# B. Total units processed by each warehouse zone
# ------------------------------------------------------------
zone_totals <- data.frame(
  Zone = 1:number_of_zones,
  TotalUnits = numeric(number_of_zones)
)

for (zone_value in 1:number_of_zones) {
  zone_total <- 0
  for (row_index in 1:nrow(warehouse_data)) {
    if (warehouse_data$Zone[row_index] == zone_value) {
      zone_total <- zone_total + warehouse_data$UnitsProcessed[row_index]
    }
  }
  zone_totals$TotalUnits[zone_value] <- zone_total
}

cat("\n============================================================\n")
cat("B. TOTAL UNITS PROCESSED PER ZONE\n")
cat("============================================================\n")
print(zone_totals, row.names = FALSE)

# ------------------------------------------------------------
# C. Average processing time per product category
# ------------------------------------------------------------
category_average_time <- data.frame(
  Category = 1:number_of_categories,
  AverageProcessingTime = numeric(number_of_categories)
)

for (category_value in 1:number_of_categories) {
  total_time <- 0
  record_count <- 0
  
  for (row_index in 1:nrow(warehouse_data)) {
    if (warehouse_data$Category[row_index] == category_value) {
      total_time <- total_time + warehouse_data$ProcessingTime[row_index]
      record_count <- record_count + 1
    }
  }
  
  if (record_count > 0) {
    category_average_time$AverageProcessingTime[category_value] <-
      round(total_time / record_count, 2)
  }
}

cat("\n============================================================\n")
cat("C. AVERAGE PROCESSING TIME PER CATEGORY\n")
cat("============================================================\n")
print(category_average_time, row.names = FALSE)

# D. Identify anomalies against each day-zone average
# ------------------------------------------------------------
processing_anomalies <- data.frame(
  Day = integer(total_records),
  Zone = integer(total_records),
  Category = integer(total_records),
  UnitsProcessed = integer(total_records),
  DailyZoneAverage = numeric(total_records),
  Anomaly = logical(total_records)
)

anomaly_row <- 0

for (day_value in 1:number_of_days) {
  for (zone_value in 1:number_of_zones) {
    daily_total <- 0
    daily_count <- 0
    
    # Calculate average for the six categories for this day and zone
    for (row_index in 1:nrow(warehouse_data)) {
      if (warehouse_data$Day[row_index] == day_value &&
          warehouse_data$Zone[row_index] == zone_value) {
        daily_total <- daily_total + warehouse_data$UnitsProcessed[row_index]
        daily_count <- daily_count + 1
      }
    }
    
    if (daily_count > 0) {
      daily_average <- daily_total / daily_count
      
      for (row_index in 1:nrow(warehouse_data)) {
        if (warehouse_data$Day[row_index] == day_value &&
            warehouse_data$Zone[row_index] == zone_value) {
          anomaly_row <- anomaly_row + 1
          units_value <- warehouse_data$UnitsProcessed[row_index]
          is_anomaly <- (units_value > daily_average * UpperThreshold) ||
            (units_value < daily_average * LowerThreshold)
          
          processing_anomalies$Day[anomaly_row] <- day_value
          processing_anomalies$Zone[anomaly_row] <- zone_value
          processing_anomalies$Category[anomaly_row] <-
            warehouse_data$Category[row_index]
          processing_anomalies$UnitsProcessed[anomaly_row] <- units_value
          processing_anomalies$DailyZoneAverage[anomaly_row] <-
            round(daily_average, 2)
          processing_anomalies$Anomaly[anomaly_row] <- is_anomaly
        }
      }
    }
  }
}

# Count anomalies using a loop and identify the first 10 flagged records
total_anomalies <- 0
for (i in 1:anomaly_row) {
  if (processing_anomalies$Anomaly[i]) {
    total_anomalies <- total_anomalies + 1
  }
}

cat("\n============================================================\n")
cat("D. PROCESSING ANOMALY DETECTION\n")
cat("============================================================\n")
cat("Records checked:", anomaly_row, "\n")
cat("Anomalies identified:", total_anomalies, "\n")
if (anomaly_row > 0) {
  cat("Anomaly rate (%):", round(total_anomalies / anomaly_row * 100, 2), "\n")
}

shown <- 0
for (i in 1:anomaly_row) {
  if (processing_anomalies$Anomaly[i] && shown < 10) {
    if (shown == 0) {
      cat("\nFirst anomaly records:\n")
    }
    print(processing_anomalies[i, ], row.names = FALSE)
    shown <- shown + 1
  }
}
if (shown == 0) {
  cat("No anomalies were identified.\n")
}

# ------------------------------------------------------------
# E. Most productive day for each zone
# ------------------------------------------------------------
peak_zone_days <- data.frame(
  Zone = 1:number_of_zones,
  Day = integer(number_of_zones),
  TotalUnits = numeric(number_of_zones)
)

for (zone_value in 1:number_of_zones) {
  highest_total <- -1
  highest_day <- 0
  
  for (day_value in 1:number_of_days) {
    daily_total <- 0
    
    for (row_index in 1:nrow(warehouse_data)) {
      if (warehouse_data$Zone[row_index] == zone_value &&
          warehouse_data$Day[row_index] == day_value) {
        daily_total <- daily_total + warehouse_data$UnitsProcessed[row_index]
      }
    }
    
    # If totals tie, keep the earlier day
    if (daily_total > highest_total) {
      highest_total <- daily_total
      highest_day <- day_value
    }
  }
  
  peak_zone_days$Day[zone_value] <- highest_day
  peak_zone_days$TotalUnits[zone_value] <- highest_total
}

cat("\n============================================================\n")
cat("E. PEAK PROCESSING DAY PER ZONE\n")
cat("============================================================\n")
print(peak_zone_days, row.names = FALSE)

# ------------------------------------------------------------
# F. Validation checks
# ------------------------------------------------------------
cat("\n============================================================\n")
cat("F. VALIDATION CHECKS\n")
cat("============================================================\n")

if (nrow(warehouse_data) == total_records && ncol(warehouse_data) == 5) {
  cat("PASS: Dataset has", total_records, "rows and 5 columns.\n")
} else {
  cat("FAIL: Dataset dimensions are incorrect.\n")
}

# Check that every day-zone-category combination appears once
combination_errors <- 0
for (day_value in 1:number_of_days) {
  for (zone_value in 1:number_of_zones) {
    for (category_value in 1:number_of_categories) {
      match_count <- 0
      for (row_index in 1:nrow(warehouse_data)) {
        if (warehouse_data$Day[row_index] == day_value &&
            warehouse_data$Zone[row_index] == zone_value &&
            warehouse_data$Category[row_index] == category_value) {
          match_count <- match_count + 1
        }
      }
      if (match_count != 1) {
        combination_errors <- combination_errors + 1
      }
    }
  }
}
if (combination_errors == 0) {
  cat("PASS: Every day-zone-category combination appears exactly once.\n")
} else {
  cat("FAIL: Combination errors found:", combination_errors, "\n")
}

# Check processing-time formula
time_errors <- 0
for (row_index in 1:nrow(warehouse_data)) {
  expected_time <- warehouse_data$UnitsProcessed[row_index] * TimePerUnit
  if (abs(warehouse_data$ProcessingTime[row_index] - expected_time) > 0.000001) {
    time_errors <- time_errors + 1
  }
}
if (time_errors == 0) {
  cat("PASS: ProcessingTime equals UnitsProcessed * 0.85 for every row.\n")
} else {
  cat("FAIL: Processing-time errors found:", time_errors, "\n")
}

# Check recovered random variation stays within -12 to +12
variation_errors <- 0
for (row_index in 1:nrow(warehouse_data)) {
  recovered_variation <- warehouse_data$UnitsProcessed[row_index] -
    BaseUnits -
    (warehouse_data$Zone[row_index] * ZoneMultiplier) -
    (warehouse_data$Category[row_index] * CategoryMultiplier)
  
  if (recovered_variation < MinVariation ||
      recovered_variation > MaxVariation) {
    variation_errors <- variation_errors + 1
  }
}
if (variation_errors == 0) {
  cat("PASS: Random variation stays between -12 and +12.\n")
} else {
  cat("FAIL: Random variation errors found:", variation_errors, "\n")
}

# Compare zone totals with the total across all warehouse records
zone_grand_total <- 0
for (i in 1:nrow(zone_totals)) {
  zone_grand_total <- zone_grand_total + zone_totals$TotalUnits[i]
}
dataset_grand_total <- 0
for (i in 1:nrow(warehouse_data)) {
  dataset_grand_total <- dataset_grand_total + warehouse_data$UnitsProcessed[i]
}

if (zone_grand_total == dataset_grand_total) {
  cat("PASS: Zone totals match the overall dataset total (",
      dataset_grand_total, " units).\n", sep = "")
} else {
  cat("FAIL: Zone totals do not match the overall dataset total.\n")
}


cat("\n============================================================\n")
cat("              FINAL SUMMARY REPORT\n")
cat("============================================================\n\n")

# Student and assessment details
cat("STUDENT DETAILS\n")
cat("------------------------------------------------------------\n")
cat("Student Name: Gaurav Bansod\n")
cat("Student ID: 2519815\n")
cat("Module Code: ACCA7022\n")
cat("Assessment: Data Manipulation\n\n")

# Dataset overview
cat("DATASET OVERVIEW\n")
cat("------------------------------------------------------------\n")
cat("Warehouse records generated:", nrow(warehouse_data), "\n")
cat("Number of columns:", ncol(warehouse_data), "\n")
cat("Operating days:", number_of_days, "\n")
cat("Warehouse zones:", number_of_zones, "\n")
cat("Product categories:", number_of_categories, "\n")
cat("Expected records:", total_records, "\n")
cat("Total units processed:", dataset_grand_total, "\n\n")

# Units processed by zone
cat("ZONE PERFORMANCE\n")
cat("------------------------------------------------------------\n")
print(zone_totals, row.names = FALSE)

# Category average processing time
cat("\nAVERAGE PROCESSING TIME BY CATEGORY\n")
cat("------------------------------------------------------------\n")
print(category_average_time, row.names = FALSE)

# Anomaly detection results
cat("\nANOMALY DETECTION RESULTS\n")
cat("------------------------------------------------------------\n")
cat("Records checked:", nrow(processing_anomalies), "\n")
cat("Anomalies identified:", total_anomalies, "\n")

if (nrow(processing_anomalies) > 0) {
  anomaly_rate <- total_anomalies /
    nrow(processing_anomalies) * 100
  
  cat("Anomaly rate (%):", round(anomaly_rate, 2), "%\n")
}

cat("\nFirst 10 anomalous records:\n")
shown <- 0

for (i in 1:nrow(processing_anomalies)) {
  if (processing_anomalies$Anomaly[i] && shown < 10) {
    print(processing_anomalies[i, ], row.names = FALSE)
    shown <- shown + 1
  }
}

if (shown == 0) {
  cat("No anomalies identified.\n")
}

# Most productive day per zone
cat("\nPEAK PRODUCTIVITY BY ZONE\n")
cat("------------------------------------------------------------\n")
print(peak_zone_days, row.names = FALSE)

# Validation results
cat("\nVALIDATION SUMMARY\n")
cat("------------------------------------------------------------\n")

if (nrow(warehouse_data) == total_records &&
    ncol(warehouse_data) == 5) {
  cat("PASS: Dataset dimensions are correct.\n")
} else {
  cat("FAIL: Dataset dimensions are incorrect.\n")
}

if (combination_errors == 0) {
  cat("PASS: Every day-zone-category combination appears once.\n")
} else {
  cat("FAIL: Combination errors:", combination_errors, "\n")
}

if (time_errors == 0) {
  cat("PASS: Processing-time calculations are correct.\n")
} else {
  cat("FAIL: Processing-time errors:", time_errors, "\n")
}

if (variation_errors == 0) {
  cat("PASS: Random variation is within the required bounds.\n")
} else {
  cat("FAIL: Random variation errors:", variation_errors, "\n")
}

if (zone_grand_total == dataset_grand_total) {
  cat("PASS: Zone totals match the dataset grand total.\n")
} else {
  cat("FAIL: Zone totals do not match the dataset total.\n")
}

# Completion
cat("\n============================================================\n")
cat("       WAREHOUSE DATA ANALYSIS COMPLETED\n")
cat("============================================================\n")
cat("Total records:", nrow(warehouse_data), "\n")
cat("Total units processed:", dataset_grand_total, "\n")
cat("Total anomalies:", total_anomalies, "\n")
cat("All displayed validation checks should be reviewed above.\n")
cat("============================================================\n")
