# =================================================================
# TITLE: Longitudinal Effects of School Boarding on Adolescent Depression: 
#        Examining the Mediating Role of Parent-child Closeness 
#        and School Connectedness
# AUTHOR: Ling Li Leng & Nurali Dayim
# DATE: 2025-08-7
#
# ANALYSIS PIPELINE:
# 1. Propensity Score Matching (Multiple Methods)
# 2. Balance Diagnostics
# 3. Treatment Effect Estimation
# 4. Parallel Mediation Analysis
# =================================================================

# ---------------------------
# 0. SETUP & DATA PREPARATION
# ---------------------------
library(MatchIt)   # For propensity score matching
library(lmtest)    # For coefficient tests
library(sandwich)  # For robust SEs
library(lavaan)    # For mediation analysis

# Load data
boarding <- read.csv("data/boarding_study.csv")

# Define covariates
covariates <- c(
  "Age_w1", "Sex", "ethnic_2", "Onlychild_w1", "hukou_type_w1",
  "migrant_w1", "academic_rank_w1", "cognitive_test_w1", "Depression_w1",
  "mum_edu_level", "dad_edu_level", "family_finan_w1", "living_parent_w1",
  "parent_marital_w2", "parent_relation_w1", "relation_parent_w1",
  "parenting_control_w1", "School_rank_2", "School_location_2", "school_belong_w1"
)

# ------------------------------
# 1. PROPENSITY SCORE MATCHING
# ------------------------------

## 1.1 Nearest Neighbor Matching (Primary)
m_match_near <- matchit(
  reformulate(covariates, "Boarding_w1"),
  data = boarding,
  method = "nearest",
  distance = "glm",
  caliper = 0.15,
  reuse.max = 1
)
match_data_near <- match.data(m_match_near)

## 1.2 Mahalanobis Matching (Sensitivity)
m_match_maha <- matchit(
  reformulate(covariates, "Boarding_w1"),
  data = boarding,
  method = "nearest",
  distance = "mahalanobis",
  caliper = 0.1
)

## 1.3 Full Matching (Sensitivity)
m_match_full <- matchit(
  reformulate(covariates, "Boarding_w1"),
  data = boarding,
  method = "full"
)

# --------------------------
# 2. BALANCE DIAGNOSTICS
# --------------------------

# Covariate labels for plots
covariate_labels <- setNames(
  c("Age", "Sex", "Ethnicity", "Only child", "Hukou", "Migrant",
    "Academic ranking", "Cognitive test", "Depressive symptom",
    "Mother education", "Father education", "Household income",
    "Household composition", "Parental marriage", "Inter-parental relationship",
    "Parent-child closeness", "Parenting control", "School academic ranking",
    "Geographic location", "School connectedness"),
  covariates
)

# Generate balance plot
love.plot(m_match_near,
          stat = "mean.diffs",
          thresholds = c(m = 0.1),
          var.names = covariate_labels,
          title = "Covariate Balance After Matching")

# -------------------------------
# 3. TREATMENT EFFECT ESTIMATION
# -------------------------------

## Primary model (Nearest Neighbor)
model_att <- lm(
  Depression_w2 ~ Boarding_w1 * living_parent_w1,
  data = match_data_near,
  weights = weights
)

# Robust results
coeftest(model_att, vcov = vcovCL, cluster = ~subclass)

# Average Treatment Effect
avg_comparisons(
  model_att,
  variables = "Boarding_w1",
  vcov = ~subclass
)

# --------------------------
# 4. MEDIATION ANALYSIS
# --------------------------

mediation_model <- '
  # Mediators
  school_belong_w2 ~ a1 * Boarding_w1
  relation_parent_w2 ~ a2 * Boarding_w1
  
  # Outcome
  Depression_w2 ~ b1 * school_belong_w2 + 
                 b2 * relation_parent_w2 + 
                 c * Boarding_w1
  
  # Effects
  indirect1 := a1 * b1  # School belonging pathway
  indirect2 := a2 * b2  # Parent closeness pathway
  total := c + (a1*b1) + (a2*b2)
'

# Fit model with bootstrapping
fit_med <- sem(mediation_model,
               data = match_data_near,
               se = "bootstrap",
               bootstrap = 5000)

# View results
summary(fit_med, standardized = TRUE, rsq = TRUE)

# Calculate proportion mediated
parameterEstimates(fit_med, standardized = TRUE) %>% 
  filter(op == ":=") %>% 
  mutate(proportion = ifelse(label == "total", 
                             NA,
                             abs(est/est[label == "total"])))

# --------------------------
# 5. SAVE RESULTS
# --------------------------

# Save workspace
save.image("analysis_results.RData")

# Save matched dataset
saveRDS(match_data_near, "output/matched_data.rds")

# Save mediation results
capture.output(
  summary(fit_med, standardized = TRUE),
  file = "output/mediation_results.txt"
)