# ============================================================
# UCI Breast Cancer Wisconsin - Clean End-to-End MLOps
# ============================================================

# -----------------------------
# 1. Libraries
# -----------------------------
library(caret)
library(randomForest)
library(data.table)
suppressMessages(library(mlflow))

# -----------------------------
# 2. Load Dataset
# -----------------------------
DATA_PATH <- "C:/Users/Dhanushkumar/OneDrive/Desktop/MLOPS PRO/MINI PROJECT/breast cancer/data.csv"

if (!file.exists(DATA_PATH)) {
  stop("Dataset not found. Check file path.")
}

data <- fread(DATA_PATH)
data <- as.data.frame(data)

# -----------------------------
# 3. Fix Column Names (IMPORTANT)
# -----------------------------

# Remove spaces & special characters
colnames(data) <- make.names(colnames(data))

# Remove completely empty columns
data <- data[, colSums(is.na(data)) < nrow(data)]

# Rename diagnosis column if needed
colnames(data)[2] <- "diagnosis"

# Remove ID column
data <- data[, -1]

# Convert diagnosis to factor
data$diagnosis <- as.factor(data$diagnosis)

# -----------------------------
# 4. Handle Missing Values
# -----------------------------

# Replace NA in numeric columns with median
for(i in 1:ncol(data)){
  if(is.numeric(data[,i])){
    data[is.na(data[,i]), i] <- median(data[,i], na.rm = TRUE)
  }
}

cat("Remaining NA values:", sum(is.na(data)), "\n")
## Remaining NA values: 0
# -----------------------------
# 5. Train-Test Split
# -----------------------------
set.seed(42)

train_index <- createDataPartition(
  y = data$diagnosis,
  p = 0.8,
  list = FALSE
)

train_set <- data[train_index, ]
test_set  <- data[-train_index, ]

# -----------------------------
# 6. MLflow (Safe Local Mode)
# -----------------------------
mlflow_set_tracking_uri("file:./mlruns")

try({
  mlflow_set_experiment("Breast_Cancer_MLOps")
  mlflow_start_run()
}, silent = TRUE)

# -----------------------------
# 7. Model Training
# -----------------------------
N_TREES <- 500

try(mlflow_log_param("model_type", "RandomForest"), silent = TRUE)
try(mlflow_log_param("ntree", N_TREES), silent = TRUE)

rf_model <- randomForest(
  diagnosis ~ .,
  data = train_set,
  ntree = N_TREES,
  importance = TRUE
)

# -----------------------------
# 8. Prediction & Evaluation
# -----------------------------
predictions <- predict(rf_model, test_set)

cm <- confusionMatrix(predictions, test_set$diagnosis)

accuracy <- as.numeric(cm$overall["Accuracy"])
sensitivity <- as.numeric(cm$byClass["Sensitivity"])

try(mlflow_log_metric("accuracy", accuracy), silent = TRUE)
try(mlflow_log_metric("sensitivity", sensitivity), silent = TRUE)

# -----------------------------
# 9. Model Versioning
# -----------------------------
MODEL_PATH <- "rf_model_v1.rds"
saveRDS(rf_model, MODEL_PATH)

try(mlflow_log_artifact(MODEL_PATH), silent = TRUE)

# -----------------------------
# 10. Final Output
# -----------------------------
cat("\n==============================\n")
## 
## ==============================
cat(" Final Model Performance\n")
##  Final Model Performance
cat("==============================\n")
## ==============================
cat(" Accuracy    :", round(accuracy, 4), "\n")
##  Accuracy    : 0.9823
cat(" Sensitivity :", round(sensitivity, 4), "\n")
##  Sensitivity : 0.9718
cat("==============================\n")
## ==============================
try(mlflow_end_run(), silent = TRUE)