# ==============================================================================
# KỊCH BẢN R CHẠY TỪNG BƯỚC (INTERACTIVE STEP-BY-STEP WORKFLOW)
# Đề tài: Tác động của chất lượng thể chế và văn hoá đến sự phát triển TMĐT
# Dữ liệu: Panel_R_Complete_All_Variables_2012_2024.xlsx (Sheet: Panel_R_complete)
# Phương pháp chính: Correlated Random Effects (CRE / Mundlak), Year Fixed Effects,
#                    Sai số chuẩn cụm theo quốc gia (HC1) & CR2 Satterthwaite.
#
# HƯỚNG DẪN SỬ DỤNG TRÊN RSTUDIO:
# - Kịch bản này đã được chia thành 11 BƯỚC độc lập, hiển thị toàn bộ bảng biểu
#   và đồ thị trực tiếp trên màn hình RStudio (Console & Plots), KHÔNG xuất ra
#   thư mục R_results bên ngoài.
# - Cách chạy: Bôi đen từng khối lệnh (từ dòng BẮT ĐẦU BƯỚC đến HẾT BƯỚC)
#   rồi nhấn tổ hợp phím Ctrl + Enter (trên Windows) hoặc Cmd + Enter (trên Mac)
#   để chạy và quan sát ngay kết quả ở cửa sổ Console / Plots bên dưới.
# - Mẹo trong RStudio: Bạn có thể nhấn nút "Outline" (góc trên bên phải cửa sổ
#   code) để nhảy nhanh giữa các Bước 0 -> Bước 11.
# ==============================================================================


# ==============================================================================
# BƯỚC 0: CÀI ĐẶT GÓI, NẠP THƯ VIỆN & THIẾT LẬP MÔI TRƯỜNG ====
# -> Cách chạy: Bôi đen toàn bộ Bước 0 và nhấn Ctrl + Enter.
# ==============================================================================

options(stringsAsFactors = FALSE, scipen = 5, width = 120, digits = 4)
set.seed(20261110)

# Tuỳ chỉnh loại trừ quốc gia thủ công (nếu cần) và cờ tự động loại dữ liệu lỗi:
EXCLUDE_ISO3      <- character()  # Ví dụ: c("MEX") nếu muốn tự loại Mexico
AUTO_DROP_INVALID <- TRUE         # TRUE: Tự động loại quốc gia vi phạm [FIX 1]

required_packages <- c(
  "readxl", "dplyr", "janitor", "plm", "lmtest", "sandwich", "car",
  "clubSandwich", "ggplot2", "corrplot", "readr"
)

new_packages <- setdiff(required_packages, rownames(utils::installed.packages()))
if (length(new_packages) > 0L) {
  message("Đang cài đặt các gói còn thiếu: ", paste(new_packages, collapse = ", "))
  install.packages(new_packages, repos = "https://cloud.r-project.org")
}

invisible(lapply(required_packages, function(pkg) {
  if (!requireNamespace(pkg, quietly = TRUE)) {
    stop("Không thể nạp gói bắt buộc: ", pkg)
  }
}))
## Registered S3 method overwritten by 'clubSandwich':
##   method    from    
##   bread.mlm sandwich
# Hàm hỗ trợ chạy an toàn và ghi thông báo trực tiếp lên màn hình Console
log_note <- function(...) {
  s <- paste0(..., collapse = "")
  cat(sprintf("\n[THÔNG BÁO] %s\n", s))
  invisible(s)
}

safe_call <- function(expr, label) {
  tryCatch(expr, error = function(e) {
    cat(sprintf("\n[LỖI KHI CHẠY] %s: %s\n", label, conditionMessage(e)))
    NULL
  })
}

cat("\n>>> HOÀN TẤT BƯỚC 0: Tất cả thư viện đã sẵn sàng!\n")
## 
## >>> HOÀN TẤT BƯỚC 0: Tất cả thư viện đã sẵn sàng!
# ==============================================================================
# BƯỚC 1: ĐỌC DỮ LIỆU EXCEL & KIỂM TRA CHẤT LƯỢNG DỮ LIỆU BẢNG (AUDIT) ====
# -> Lưu ý: Đặt file Excel cùng thư mục làm việc (Session -> Set Working Directory)
#    hoặc nếu R không tìm thấy trong thư mục hiện tại, cửa sổ chọn file sẽ hiện ra.
# -> Cách chạy: Bôi đen toàn bộ Bước 1 và nhấn Ctrl + Enter.
# ==============================================================================

base_dir <- getwd()
input_files <- list.files(
  base_dir,
  pattern = "^Panel_R_Complete_All_Variables_2012_2024.*[.]xlsx$",
  full.names = TRUE
)

if (!length(input_files)) {
  cat("\nKhông tìm thấy file Excel trong thư mục hiện tại (", base_dir, ").\n", sep = "")
  if (interactive()) {
    cat("Vui lòng chọn file Excel 'Panel_R_Complete_All_Variables_2012_2024.xlsx' trong hộp thoại...\n")
    input_path <- file.choose()
  } else {
    stop("Không tìm thấy file Excel trong thư mục: ", base_dir)
  }
} else {
  if (length(input_files) > 1L) {
    log_note("Tìm thấy nhiều file Excel khớp tên. Đang sử dụng: ", basename(input_files[1]))
  }
  input_path <- input_files[1]
}

log_note("Đang đọc dữ liệu từ file: ", basename(input_path))
## 
## [THÔNG BÁO] Đang đọc dữ liệu từ file: Panel_R_Complete_All_Variables_2012_2024.xlsx.xlsx
df <- readxl::read_excel(input_path, sheet = "Panel_R_complete") |>
  janitor::clean_names() |>
  dplyr::mutate(
    iso3 = toupper(trimws(as.character(iso3))),
    country = as.character(country),
    year = as.integer(year)
  ) |>
  dplyr::arrange(iso3, year) |>
  as.data.frame()

# Khai báo danh sách các nhóm biến trong mô hình
culture_vars <- c("pdi", "idv", "mas", "uai", "lto", "ivr")
wgi_vars     <- c("va", "pv", "ge", "rq", "rl", "cc")
controls_full <- c(
  "ln_gdppc", "ln_population", "internet_users_pct",
  "private_credit_pct_gdp", "trade_open_pct_gdp", "secondary_enrollment_pct"
)
controls_stage1 <- c("ln_gdppc", "ln_population")
controls_stage2 <- c(controls_stage1, "internet_users_pct")
controls_stage3 <- c(controls_stage2, "private_credit_pct_gdp", "trade_open_pct_gdp")
controls_stage4 <- controls_full

model_vars <- unique(c("ln_ecom", "iq_avg", wgi_vars, culture_vars, controls_full))
other_needed <- c(
  "iso3", "country", "year", "ecom_musd", "population_total",
  "observed_only_sample", "conservative_sample", "high_risk_cell_count"
)

# Kiểm tra cấu trúc cột và khóa chính (iso3 - year)
missing_cols <- setdiff(c(model_vars, other_needed), names(df))
if (length(missing_cols)) stop("Thiếu các cột trong Excel: ", paste(missing_cols, collapse = ", "))
if (anyNA(df[c("iso3", "year")])) stop("Cột khóa iso3 hoặc year có giá trị NA.")
if (anyDuplicated(df[c("iso3", "year")])) stop("Có dòng trùng lặp cặp quốc gia - năm (iso3, year).")
if (any(df$ecom_musd <= 0, na.rm = TRUE)) stop("ecom_musd có giá trị <= 0, không thể lấy logarit.")
if (any(df$population_total <= 0, na.rm = TRUE)) stop("population_total có giá trị <= 0.")
if (any(!vapply(df[model_vars], is.numeric, logical(1)))) {
  stop("Có biến mô hình không phải dạng số (numeric). Hãy kiểm tra định dạng ô trong Excel.")
}

# [FIX 1] Kiểm tra tính hợp lý của các biến kiểm soát dạng tỷ lệ phần trăm (%)
pct_vars <- c("internet_users_pct", "private_credit_pct_gdp",
              "trade_open_pct_gdp", "secondary_enrollment_pct")
invalid_tbl <- do.call(rbind, lapply(pct_vars, function(v) {
  non_positive <- df[[v]] <= 0
  n_unique <- stats::ave(df[[v]], df$iso3, FUN = function(z) length(unique(z)))
  n_years <- stats::ave(df[[v]], df$iso3, FUN = length)
  flat <- n_unique == 1 & n_years > 3
  hit <- non_positive | flat
  if (!any(hit)) return(NULL)
  data.frame(
    iso3 = df$iso3[hit], year = df$year[hit], variable = v,
    value = df[[v]][hit],
    problem = ifelse(non_positive[hit], "Tỷ lệ phần trăm <= 0", "Không đổi suốt các năm")
  )
}))

if (!is.null(invalid_tbl)) {
  bad_iso <- sort(unique(invalid_tbl$iso3))
  cat("\n=== [CẢNH BÁO DỮ LIỆU - FIX 1] PHÁT HIỆN GIÁ TRỊ KIỂM SOÁT BẤT THƯỜNG ===\n")
  print(invalid_tbl, row.names = FALSE)
  if (AUTO_DROP_INVALID) {
    EXCLUDE_ISO3 <- union(EXCLUDE_ISO3, bad_iso)
    log_note("Đã tự động loại quốc gia bị lỗi khỏi phân tích: ", paste(bad_iso, collapse = ", "))
  }
} else {
  cat("\n[KIỂM TRA FIX 1]: Tất cả các biến kiểm soát tỷ lệ % đều hợp lệ (PASS).\n")
}
## 
## [KIỂM TRA FIX 1]: Tất cả các biến kiểm soát tỷ lệ % đều hợp lệ (PASS).
# [FIX 7] Kiểm tra đơn vị của ecom_musd (triệu USD hiện hành)
if ("gdppc_const2015_usd" %in% names(df)) {
  ecom_share <- df$ecom_musd * 1e6 / (df$gdppc_const2015_usd * df$population_total)
  ecom_step <- stats::ave(log(df$ecom_musd), df$iso3, FUN = function(z) c(NA, diff(z)))
  unit_bad <- ecom_share < 0.001 | (is.finite(ecom_step) & abs(ecom_step) > 2.3)
  if (any(unit_bad)) {
    cat("\n=== [LỖI ĐƠN VỊ - FIX 7] CÁC DÒNG CÓ ECOM_MUSD LỆCH ĐƠN VỊ ===\n")
    print(df[unit_bad, c("iso3", "year", "ecom_musd")], row.names = FALSE)
    stop("ecom_musd có giá trị nhỏ/lớn bất thường (lệch khoảng 1.000 lần) tại: ",
         paste(sort(unique(df$iso3[unit_bad])), collapse = ", "))
  } else {
    cat("[KIỂM TRA FIX 7]: Đơn vị biến phụ thuộc ecom_musd đồng nhất (PASS).\n")
  }
}
## [KIỂM TRA FIX 7]: Đơn vị biến phụ thuộc ecom_musd đồng nhất (PASS).
if (length(EXCLUDE_ISO3)) {
  log_note("Các quốc gia bị loại khỏi toàn bộ phân tích: ", paste(EXCLUDE_ISO3, collapse = ", "))
  df <- df[!(df$iso3 %in% EXCLUDE_ISO3), , drop = FALSE]
}

# Tổng hợp thông tin cấu trúc bảng (Panel Audit) và in ra màn hình
pdata <- plm::pdata.frame(df, index = c("iso3", "year"), drop.index = FALSE)
panel_n <- nrow(df)
panel_countries <- dplyr::n_distinct(df$iso3)
panel_years <- dplyr::n_distinct(df$year)
balanced <- plm::is.pbalanced(pdata)
consecutive <- all(plm::is.pconsecutive(pdata))

consistency <- data.frame(
  Chi_tieu_kiem_tra = c(
    "Tổng số quan sát (N)",
    "Số quốc gia (N_countries)",
    "Số năm (T)",
    "Bảng cân bằng (Balanced Panel: 1=Có, 0=Không)",
    "Chuỗi năm liên tục (Consecutive Years: 1=Có, 0=Không)",
    "Số dòng trùng khóa (iso3 - year)",
    "Sai số tuyệt đối lớn nhất của công thức IQ_avg",
    "Sai số tuyệt đối lớn nhất của công thức ln_ecom"
  ),
  Gia_tri = c(
    panel_n, panel_countries, panel_years, as.numeric(balanced),
    as.numeric(consecutive), 0,
    max(abs(df$iq_avg - rowMeans(df[wgi_vars]))),
    max(abs(df$ln_ecom - log(df$ecom_musd)))
  )
)

cat("\n================ BẢNG 1A: KẾT QUẢ KIỂM TRA CẤU TRÚC PANEL ================\n")
## 
## ================ BẢNG 1A: KẾT QUẢ KIỂM TRA CẤU TRÚC PANEL ================
print(consistency, row.names = FALSE)
##                                      Chi_tieu_kiem_tra   Gia_tri
##                                   Tổng số quan sát (N) 4.810e+02
##                              Số quốc gia (N_countries) 3.700e+01
##                                             Số năm (T) 1.300e+01
##          Bảng cân bằng (Balanced Panel: 1=Có, 0=Không) 1.000e+00
##  Chuỗi năm liên tục (Consecutive Years: 1=Có, 0=Không) 1.000e+00
##                       Số dòng trùng khóa (iso3 - year) 0.000e+00
##         Sai số tuyệt đối lớn nhất của công thức IQ_avg 3.553e-15
##        Sai số tuyệt đối lớn nhất của công thức ln_ecom 5.151e-14
missing_tbl <- data.frame(
  variable = model_vars,
  missing_n = vapply(df[model_vars], function(x) sum(is.na(x)), integer(1)),
  missing_pct = 100 * vapply(df[model_vars], function(x) mean(is.na(x)), numeric(1))
)
cat("\n================ BẢNG 1B: KIỂM TRA GIÁ TRỊ KHUYẾT THIẾU (MISSING) ================\n")
## 
## ================ BẢNG 1B: KIỂM TRA GIÁ TRỊ KHUYẾT THIẾU (MISSING) ================
print(missing_tbl, row.names = FALSE)
##                  variable missing_n missing_pct
##                   ln_ecom         0           0
##                    iq_avg         0           0
##                        va         0           0
##                        pv         0           0
##                        ge         0           0
##                        rq         0           0
##                        rl         0           0
##                        cc         0           0
##                       pdi         0           0
##                       idv         0           0
##                       mas         0           0
##                       uai         0           0
##                       lto         0           0
##                       ivr         0           0
##                  ln_gdppc         0           0
##             ln_population         0           0
##        internet_users_pct         0           0
##    private_credit_pct_gdp         0           0
##        trade_open_pct_gdp         0           0
##  secondary_enrollment_pct         0           0
country_count <- df |>
  dplyr::group_by(iso3, country) |>
  dplyr::summarise(
    n_years = dplyr::n_distinct(year),
    first_year = min(year),
    last_year = max(year),
    .groups = "drop"
  )
cat("\n================ BẢNG 1C: DANH SÁCH QUỐC GIA TRONG MẪU (37 NƯỚC) ================\n")
## 
## ================ BẢNG 1C: DANH SÁCH QUỐC GIA TRONG MẪU (37 NƯỚC) ================
print(as.data.frame(country_count), row.names = FALSE)
##  iso3                      country n_years first_year last_year
##   AUS                    Australia      13       2012      2024
##   AUT                      Austria      13       2012      2024
##   BEL                      Belgium      13       2012      2024
##   BGR                     Bulgaria      13       2012      2024
##   CAN                       Canada      13       2012      2024
##   CHN                        China      13       2012      2024
##   COL                     Colombia      13       2012      2024
##   CZE                      Czechia      13       2012      2024
##   DEU                      Germany      13       2012      2024
##   DNK                      Denmark      13       2012      2024
##   ESP                        Spain      13       2012      2024
##   EST                      Estonia      13       2012      2024
##   FIN                      Finland      13       2012      2024
##   FRA                       France      13       2012      2024
##   GBR               United Kingdom      13       2012      2024
##   GRC                       Greece      13       2012      2024
##   HKG         China, Hong Kong SAR      13       2012      2024
##   HRV                      Croatia      13       2012      2024
##   HUN                      Hungary      13       2012      2024
##   JPN                        Japan      13       2012      2024
##   KOR            Republic of Korea      13       2012      2024
##   LTU                    Lithuania      13       2012      2024
##   LUX                   Luxembourg      13       2012      2024
##   MEX                       Mexico      13       2012      2024
##   MLT                        Malta      13       2012      2024
##   MYS                     Malaysia      13       2012      2024
##   NLD Netherlands (Kingdom of the)      13       2012      2024
##   NOR                       Norway      13       2012      2024
##   PHL                  Philippines      13       2012      2024
##   POL                       Poland      13       2012      2024
##   PRT                     Portugal      13       2012      2024
##   SGP                    Singapore      13       2012      2024
##   SRB                       Serbia      13       2012      2024
##   SVK                     Slovakia      13       2012      2024
##   SVN                     Slovenia      13       2012      2024
##   THA                     Thailand      13       2012      2024
##   USA     United States of America      13       2012      2024
# ==============================================================================
# BƯỚC 2: THỐNG KÊ MÔ TẢ, MA TRẬN TƯƠNG QUAN, VIF & ĐỒ THỊ ====
# -> Cách chạy: Bạn có thể chạy từng mục nhỏ (2A, 2B, 2C, 2D) hoặc bôi đen
#    cả Bước 2 rồi nhấn Ctrl + Enter. Đồ thị sẽ hiện ngay ở tab "Plots".
# ==============================================================================

# --- 2A. Thống kê mô tả toàn mẫu và theo từng năm ---
descriptive_vars <- unique(c("ecom_musd", "ln_ecom", "iq_avg", wgi_vars,
                             culture_vars, controls_full))
descriptive_stats <- do.call(rbind, lapply(descriptive_vars, function(v) {
  x <- df[[v]]
  data.frame(
    variable = v,
    N        = sum(!is.na(x)),
    Mean     = round(mean(x, na.rm = TRUE), 3),
    SD       = round(sd(x, na.rm = TRUE), 3),
    Min      = round(min(x, na.rm = TRUE), 3),
    P25      = round(unname(quantile(x, .25, na.rm = TRUE)), 3),
    Median   = round(median(x, na.rm = TRUE), 3),
    P75      = round(unname(quantile(x, .75, na.rm = TRUE)), 3),
    Max      = round(max(x, na.rm = TRUE), 3)
  )
}))

cat("\n================ BẢNG 2A: THỐNG KÊ MÔ TẢ CÁC BIẾN TRONG MÔ HÌNH ================\n")
## 
## ================ BẢNG 2A: THỐNG KÊ MÔ TẢ CÁC BIẾN TRONG MÔ HÌNH ================
print(descriptive_stats, row.names = FALSE)
##                  variable   N       Mean          SD     Min       P25     Median        P75          Max
##                 ecom_musd 481 584557.343 1568384.033 869.000 20988.000 103807.000 285470.510 12407741.000
##                   ln_ecom 481     11.439       1.991   6.767     9.952     11.550     12.562       16.334
##                    iq_avg 481      0.884       0.675  -0.626     0.416      0.987      1.449        1.900
##                        va 481      0.817       0.766  -1.741     0.295      1.031      1.418        1.870
##                        pv 481      0.515       0.639  -1.444     0.195      0.713      0.969        1.418
##                        ge 481      1.113       0.654  -0.197     0.610      1.150      1.694        2.241
##                        rq 481      1.050       0.641  -0.267     0.514      1.083      1.632        2.194
##                        rl 481      0.908       0.800  -1.115     0.350      1.083      1.543        2.097
##                        cc 481      0.901       0.893  -0.961     0.158      0.825      1.675        2.326
##                       pdi 481     57.568      21.700  11.000    40.000     60.000     70.000      104.000
##                       idv 481     50.568      23.365  13.000    27.000     55.000     69.000       91.000
##                       mas 481     50.541      22.248   8.000    39.000     50.000     64.000      110.000
##                       uai 481     66.703      24.535   8.000    50.000     70.000     86.000      112.000
##                       lto 481     54.306      21.838  13.098    36.020     52.141     70.025      100.000
##                       ivr 481     47.038      19.858  15.625    29.464     45.536     62.723       97.321
##                  ln_gdppc 481     10.075       0.820   7.837     9.484     10.157     10.710       11.616
##             ln_population 481     16.614       1.672  12.948    15.535     16.193     17.762       21.069
##        internet_users_pct 481     81.448      14.236  26.460    74.700     85.001     92.000       99.769
##    private_credit_pct_gdp 481     89.026      44.406  19.057    50.384     86.661    116.009      264.447
##        trade_open_pct_gdp 481    122.059      84.790  23.140    66.429    100.359    150.966      442.620
##  secondary_enrollment_pct 481    107.903      16.419  73.246    99.329    104.321    112.536      164.080
by_year <- df |>
  dplyr::group_by(year) |>
  dplyr::summarise(
    N_countries      = dplyr::n_distinct(iso3),
    median_ecom_musd = round(median(ecom_musd, na.rm = TRUE), 2),
    mean_ln_ecom     = round(mean(ln_ecom, na.rm = TRUE), 3),
    mean_iq_avg      = round(mean(iq_avg, na.rm = TRUE), 3),
    .groups = "drop"
  )

cat("\n================ BẢNG 2B: XU HƯỚNG TRUNG VỊ TMĐT & THỂ CHẾ THEO NĂM ================\n")
## 
## ================ BẢNG 2B: XU HƯỚNG TRUNG VỊ TMĐT & THỂ CHẾ THEO NĂM ================
print(as.data.frame(by_year), row.names = FALSE)
##  year N_countries median_ecom_musd mean_ln_ecom mean_iq_avg
##  2012          37            77287        11.00       0.896
##  2013          37            88988        11.09       0.882
##  2014          37            90203        11.20       0.900
##  2015          37            89612        11.14       0.904
##  2016          37            76039        11.19       0.895
##  2017          37            92999        11.34       0.895
##  2018          37           108732        11.48       0.902
##  2019          37           127184        11.50       0.904
##  2020          37           120861        11.51       0.877
##  2021          37           110236        11.68       0.884
##  2022          37           155009        11.75       0.868
##  2023          37           167098        11.87       0.853
##  2024          37           155923        11.95       0.831
# --- 2B. Ma trận tương quan Pearson & Biểu đồ Heatmap trên cửa sổ Plots ---
cor_vars <- unique(c("iq_avg", wgi_vars, culture_vars, controls_full))
cor_matrix <- stats::cor(df[cor_vars], use = "pairwise.complete.obs")

cat("\n================ BẢNG 2C: MA TRẬN TƯƠNG QUAN PEARSON ================\n")
## 
## ================ BẢNG 2C: MA TRẬN TƯƠNG QUAN PEARSON ================
print(round(cor_matrix, 3))
##                          iq_avg     va     pv     ge     rq     rl     cc    pdi    idv    mas    uai    lto    ivr
## iq_avg                    1.000  0.841  0.825  0.950  0.940  0.990  0.965 -0.702  0.633 -0.248 -0.230  0.183  0.150
## va                        0.841  1.000  0.664  0.692  0.695  0.833  0.728 -0.680  0.692 -0.236  0.138  0.009  0.254
## pv                        0.825  0.664  1.000  0.723  0.692  0.796  0.716 -0.485  0.427 -0.168 -0.036  0.364 -0.175
## ge                        0.950  0.692  0.723  1.000  0.926  0.943  0.956 -0.630  0.543 -0.213 -0.369  0.194  0.213
## rq                        0.940  0.695  0.692  0.926  1.000  0.924  0.949 -0.635  0.573 -0.205 -0.432  0.136  0.182
## rl                        0.990  0.833  0.796  0.943  0.924  1.000  0.956 -0.729  0.623 -0.275 -0.212  0.186  0.133
## cc                        0.965  0.728  0.716  0.956  0.949  0.956  1.000 -0.683  0.604 -0.251 -0.366  0.155  0.184
## pdi                      -0.702 -0.680 -0.485 -0.630 -0.635 -0.729 -0.683  1.000 -0.649  0.265  0.091  0.017 -0.273
## idv                       0.633  0.692  0.427  0.543  0.573  0.623  0.604 -0.649  1.000  0.020 -0.132 -0.045  0.298
## mas                      -0.248 -0.236 -0.168 -0.213 -0.205 -0.275 -0.251  0.265  0.020  1.000  0.040  0.120  0.018
## uai                      -0.230  0.138 -0.036 -0.369 -0.432 -0.212 -0.366  0.091 -0.132  0.040  1.000  0.025 -0.100
## lto                       0.183  0.009  0.364  0.194  0.136  0.186  0.155  0.017 -0.045  0.120  0.025  1.000 -0.591
## ivr                       0.150  0.254 -0.175  0.213  0.182  0.133  0.184 -0.273  0.298  0.018 -0.100 -0.591  1.000
## ln_gdppc                  0.910  0.718  0.702  0.911  0.869  0.901  0.912 -0.658  0.597 -0.152 -0.235  0.162  0.278
## ln_population            -0.368 -0.410 -0.559 -0.196 -0.286 -0.347 -0.259  0.180 -0.062  0.363 -0.163 -0.101  0.167
## internet_users_pct        0.715  0.561  0.623  0.693  0.658  0.708  0.703 -0.489  0.476 -0.144 -0.179  0.219  0.115
## private_credit_pct_gdp    0.333 -0.005  0.153  0.446  0.427  0.361  0.446 -0.179 -0.040 -0.139 -0.477  0.101 -0.017
## trade_open_pct_gdp        0.236 -0.020  0.335  0.235  0.332  0.206  0.253  0.091 -0.136 -0.060 -0.230  0.282 -0.239
## secondary_enrollment_pct  0.547  0.550  0.366  0.476  0.493  0.543  0.556 -0.484  0.494 -0.309  0.017 -0.080  0.242
##                          ln_gdppc ln_population internet_users_pct private_credit_pct_gdp trade_open_pct_gdp
## iq_avg                      0.910        -0.368              0.715                  0.333              0.236
## va                          0.718        -0.410              0.561                 -0.005             -0.020
## pv                          0.702        -0.559              0.623                  0.153              0.335
## ge                          0.911        -0.196              0.693                  0.446              0.235
## rq                          0.869        -0.286              0.658                  0.427              0.332
## rl                          0.901        -0.347              0.708                  0.361              0.206
## cc                          0.912        -0.259              0.703                  0.446              0.253
## pdi                        -0.658         0.180             -0.489                 -0.179              0.091
## idv                         0.597        -0.062              0.476                 -0.040             -0.136
## mas                        -0.152         0.363             -0.144                 -0.139             -0.060
## uai                        -0.235        -0.163             -0.179                 -0.477             -0.230
## lto                         0.162        -0.101              0.219                  0.101              0.282
## ivr                         0.278         0.167              0.115                 -0.017             -0.239
## ln_gdppc                    1.000        -0.237              0.765                  0.410              0.259
## ln_population              -0.237         1.000             -0.264                  0.138             -0.612
## internet_users_pct          0.765        -0.264              1.000                  0.294              0.210
## private_credit_pct_gdp      0.410         0.138              0.294                  1.000              0.202
## trade_open_pct_gdp          0.259        -0.612              0.210                  0.202              1.000
## secondary_enrollment_pct    0.508        -0.186              0.358                  0.172             -0.040
##                          secondary_enrollment_pct
## iq_avg                                      0.547
## va                                          0.550
## pv                                          0.366
## ge                                          0.476
## rq                                          0.493
## rl                                          0.543
## cc                                          0.556
## pdi                                        -0.484
## idv                                         0.494
## mas                                        -0.309
## uai                                         0.017
## lto                                        -0.080
## ivr                                         0.242
## ln_gdppc                                    0.508
## ln_population                              -0.186
## internet_users_pct                          0.358
## private_credit_pct_gdp                      0.172
## trade_open_pct_gdp                         -0.040
## secondary_enrollment_pct                    1.000
safe_call({
  corrplot::corrplot(
    cor_matrix, type = "upper", method = "color", tl.col = "black",
    tl.cex = 0.75, tl.srt = 45, addCoef.col = "black", number.cex = 0.50,
    title = "Ma tran tuong quan giua cac bien giai thich", mar = c(0, 0, 2, 0)
  )
}, "Vẽ biểu đồ nhiệt ma trận tương quan (Correlation Heatmap)")

# --- 2C. Biểu đồ xu hướng doanh số TMĐT trung vị qua các năm (2012-2024) ---
safe_call({
  p_trend <- ggplot2::ggplot(by_year, ggplot2::aes(x = year, y = median_ecom_musd)) +
    ggplot2::geom_line(linewidth = 1, color = "#1f77b4") +
    ggplot2::geom_point(size = 2.5, color = "#d62728") +
    ggplot2::scale_x_continuous(breaks = sort(unique(by_year$year))) +
    ggplot2::labs(
      title = "Doanh số thương mại điện tử trung vị qua các năm (2012 - 2024)",
      subtitle = paste0("Mẫu gồm ", panel_countries, " quốc gia (", panel_n, " quan sát)"),
      x = "Năm", y = "Doanh số TMĐT trung vị (Triệu USD)"
    ) +
    ggplot2::theme_minimal(base_size = 12)
  print(p_trend)
}, "Vẽ biểu đồ xu hướng TMĐT")

# --- 2D. Kiểm tra đa cộng tuyến (VIF) ---
vif_formula <- stats::reformulate(
  c("iq_avg", culture_vars, controls_full), response = "ln_ecom"
)
vif_lm <- stats::lm(vif_formula, data = df)
vif_raw <- safe_call(car::vif(vif_lm), "Tính hệ số phóng đại phương sai VIF")

if (!is.null(vif_raw)) {
  if (is.matrix(vif_raw)) {
    vif_tbl <- data.frame(variable = rownames(vif_raw), round(vif_raw, 3),
                          row.names = NULL, check.names = FALSE)
  } else {
    vif_tbl <- data.frame(variable = names(vif_raw), VIF = round(as.numeric(vif_raw), 3))
  }
  cat("\n================ BẢNG 2D: HỆ SỐ PHÓNG ĐẠI PHƯƠNG SAI (VIF) ================\n")
  cat("(Lưu ý: Không đưa đồng thời iq_avg và 6 biến WGI vào cùng 1 mô hình VIF vì iq_avg là trung bình cộng)\n")
  print(vif_tbl, row.names = FALSE)
}
## 
## ================ BẢNG 2D: HỆ SỐ PHÓNG ĐẠI PHƯƠNG SAI (VIF) ================
## (Lưu ý: Không đưa đồng thời iq_avg và 6 biến WGI vào cùng 1 mô hình VIF vì iq_avg là trung bình cộng)
##                  variable    VIF
##                    iq_avg 10.300
##                       pdi  2.749
##                       idv  3.110
##                       mas  1.615
##                       uai  1.897
##                       lto  2.160
##                       ivr  2.493
##                  ln_gdppc 11.893
##             ln_population  3.924
##        internet_users_pct  2.622
##    private_credit_pct_gdp  2.212
##        trade_open_pct_gdp  3.496
##  secondary_enrollment_pct  1.821
# ==============================================================================
# BƯỚC 3: KHỞI TẠO CÁC HÀM ƯỚC LƯỢNG & HÀM HIỂN THỊ BẢNG KẾT QUẢ ====
# -> Bước này nạp các hàm tính toán mô hình CRE/Mundlak, sai số chuẩn cụm HC1,
#    sai số chuẩn CR2 Satterthwaite và hàm in bảng tổng hợp lên màn hình R.
# -> Cách chạy: Bôi đen toàn bộ Bước 3 và nhấn Ctrl + Enter.
# ==============================================================================

make_formula <- function(y = "ln_ecom", institution = "iq_avg", culture = culture_vars,
                         controls = controls_full, add_mundlak = FALSE) {
  explanatory <- unique(c(institution, culture, controls))
  if (add_mundlak) {
    explanatory <- c(explanatory, paste0(c(institution, controls), "_m"))
  }
  stats::reformulate(c(explanatory, "factor(year)"), response = y)
}

prepare_cre_data <- function(dat, institution = "iq_avg", culture = culture_vars,
                             controls = controls_full, y = "ln_ecom") {
  needed <- unique(c("iso3", "year", y, institution, culture, controls))
  if (length(setdiff(needed, names(dat)))) {
    stop("Thiếu biến trong dữ liệu: ", paste(setdiff(needed, names(dat)), collapse = ", "))
  }
  dat <- dat[stats::complete.cases(dat[needed]), , drop = FALSE]
  if (nrow(dat) < 30L || dplyr::n_distinct(dat$iso3) < 6L) {
    stop("Số quan sát hoặc số quốc gia quá ít để ước lượng CRE.")
  }
  dat |>
    dplyr::arrange(iso3, year) |>
    dplyr::group_by(iso3) |>
    dplyr::mutate(
      dplyr::across(dplyr::all_of(c(institution, controls)),
                    ~mean(.x), .names = "{.col}_m")
    ) |>
    dplyr::ungroup() |>
    as.data.frame()
}

fit_cre <- function(dat, institution = "iq_avg", culture = culture_vars,
                    controls = controls_full, y = "ln_ecom") {
  dat <- prepare_cre_data(dat, institution, culture, controls, y)
  pdat <- plm::pdata.frame(dat, index = c("iso3", "year"), drop.index = FALSE)
  f <- make_formula(y, institution, culture, controls, add_mundlak = TRUE)
  # [FIX 2] Tự động chuyển sang Wallace-Hussain nếu mẫu con không cân bằng làm Swamy-Arora bị suy biến
  tryCatch(
    plm::plm(f, data = pdat, model = "random", effect = "individual",
             random.method = "swar"),
    error = function(e) {
      message("  [Lưu ý FIX 2] Swamy-Arora không khả dụng trên mẫu không cân bằng; tự động chuyển sang Wallace-Hussain.")
      plm::plm(f, data = pdat, model = "random", effect = "individual",
               random.method = "walhus")
    }
  )
}

fit_noncre <- function(dat, method = c("pooling", "within", "random"),
                       with_culture = TRUE) {
  method <- match.arg(method)
  cult <- if (with_culture) culture_vars else character()
  f <- make_formula(culture = cult)
  needed <- unique(c("iso3", "year", "ln_ecom", "iq_avg", controls_full, cult))
  dat <- dat[stats::complete.cases(dat[needed]), , drop = FALSE]
  pdat <- plm::pdata.frame(dat, index = c("iso3", "year"), drop.index = FALSE)
  if (method == "random") {
    plm::plm(f, data = pdat, model = method, effect = "individual", random.method = "swar")
  } else {
    plm::plm(f, data = pdat, model = method, effect = "individual")
  }
}

vcov_country <- function(m) {
  plm::vcovHC(m, method = "arellano", type = "HC1", cluster = "group")
}

model_n <- function(m) if (is.null(m)) NA_integer_ else length(stats::residuals(m))
model_countries <- function(m) {
  if (is.null(m)) return(NA_integer_)
  length(unique(as.character(plm::index(m)[[1]])))
}

empty_tidy <- function() {
  data.frame(term = character(), estimate = numeric(), std_error = numeric(),
             statistic = numeric(), df = numeric(), p_value = numeric())
}

get_coefs <- function(m, inference = c("cluster", "cr2", "dk", "double")) {
  inference <- match.arg(inference)
  if (is.null(m)) return(empty_tidy())
  if (inference == "cr2") {
    x <- safe_call(as.data.frame(clubSandwich::coef_test(
      m, vcov = "CR2", cluster = "individual", test = "Satterthwaite"
    )), "CR2 estimation")
    if (is.null(x)) return(empty_tidy())
    return(data.frame(
      term = as.character(x$Coef), estimate = as.numeric(x$beta),
      std_error = as.numeric(x$SE), statistic = as.numeric(x$tstat),
      df = as.numeric(x$df_Satt), p_value = as.numeric(x$p_Satt)
    ))
  }
  V <- safe_call(switch(inference,
    cluster = vcov_country(m),
    dk      = plm::vcovSCC(m, type = "HC1", maxlag = 2),
    double  = plm::vcovDC(m, type = "HC1")
  ), paste0("Covariance: ", inference))
  if (is.null(V)) return(empty_tidy())
  test <- safe_call(lmtest::coeftest(m, vcov. = V),
                    paste0("Coefficient test: ", inference))
  if (is.null(test)) return(empty_tidy())
  data.frame(
    term = rownames(test), estimate = unname(test[, 1]),
    std_error = unname(test[, 2]), statistic = unname(test[, 3]),
    df = NA_real_, p_value = unname(test[, 4]), row.names = NULL
  )
}

collect_coefs <- function(model, model_label, inference = "cluster", keep = NULL) {
  x <- get_coefs(model, inference)
  if (!nrow(x)) return(data.frame())
  if (!is.null(keep)) x <- x[x$term %in% keep, , drop = FALSE]
  if (!nrow(x)) return(data.frame())
  cbind(
    data.frame(model = model_label, inference = inference,
               N = model_n(model), countries = model_countries(model)),
    x
  )
}

signif_mark <- function(p) {
  if (!is.finite(p)) return("")
  if (p < .01) return("***")
  if (p < .05) return("**")
  if (p < .10) return("*")
  ""
}

# Hàm in bảng hồi quy tổng hợp trực tiếp ra màn hình Console (thay cho xuất file HTML)
print_model_table <- function(models, heading, keep = NULL, inference = "cluster") {
  models <- models[!vapply(models, is.null, logical(1))]
  if (!length(models)) return(invisible(NULL))
  tables <- lapply(models, get_coefs, inference = inference)
  all_terms <- unique(unlist(lapply(tables, function(x) x$term)))
  # Ẩn các biến giả năm factor(year) cho bảng gọn đẹp dễ nhìn trên Console
  all_terms <- all_terms[!grepl("^factor\\(year\\)", all_terms)]
  if (!is.null(keep)) all_terms <- intersect(keep, all_terms)
  if (!length(all_terms)) return(invisible(NULL))

  out_df <- data.frame(Variable = c(all_terms, "Observations (N)", "Countries"),
                       stringsAsFactors = FALSE)
  for (j in seq_along(models)) {
    tb <- tables[[j]]
    col_vals <- character(length(all_terms) + 2L)
    for (i in seq_along(all_terms)) {
      z <- tb[tb$term == all_terms[i], , drop = FALSE]
      if (nrow(z) == 1L) {
        col_vals[i] <- sprintf("%.4f%s (%.4f)", z$estimate,
                               signif_mark(z$p_value), z$std_error)
      } else {
        col_vals[i] <- ""
      }
    }
    col_vals[length(all_terms) + 1L] <- as.character(model_n(models[[j]]))
    col_vals[length(all_terms) + 2L] <- as.character(model_countries(models[[j]]))
    out_df[[names(models)[j]]] <- col_vals
  }
  cat("\n==============================================================================\n")
  cat(heading, "\n")
  cat("Ghi chú: Hệ số ước lượng kèm sai số chuẩn (", toupper(inference), ") trong ngoặc đơn.\n", sep = "")
  cat("Mức ý nghĩa: * p < 0.10; ** p < 0.05; *** p < 0.01. Đã kiểm soát hiệu ứng năm.\n")
  cat("==============================================================================\n")
  print(out_df, row.names = FALSE, right = FALSE)
  invisible(out_df)
}

cat("\n>>> HOÀN TẤT BƯỚC 3: Đã nạp toàn bộ hàm ước lượng và hàm hiển thị bảng!\n")
## 
## >>> HOÀN TẤT BƯỚC 3: Đã nạp toàn bộ hàm ước lượng và hàm hiển thị bảng!
# ==============================================================================
# BƯỚC 4: ƯỚC LƯỢNG CRE VỚI 4 TẦNG BIẾN KIỂM SOÁT (M1 -> M4) ====
# -> M1: Chỉ kiểm soát GDP bình quân & Dân số
# -> M2: Thêm tỷ lệ người dùng Internet
# -> M3: Thêm Tín dụng tư nhân & Độ mở thương mại
# -> M4: Mô hình đầy đủ (thêm Giáo dục trung học)
# -> Cách chạy: Bôi đen toàn bộ Bước 4 và nhấn Ctrl + Enter.
# ==============================================================================

control_stages <- list(
  M1_GDP_Pop        = controls_stage1,
  M2_Internet       = controls_stage2,
  M3_Finance_Trade  = controls_stage3,
  M4_Education_Full = controls_stage4
)

nested_models <- lapply(names(control_stages), function(lbl) {
  safe_call(fit_cre(df, controls = control_stages[[lbl]]),
            paste0("Nested CRE: ", lbl))
})
names(nested_models) <- names(control_stages)

# In bảng so sánh 4 tầng mô hình M1 -> M4 trực tiếp lên Console
print_model_table(
  nested_models,
  heading = "BẢNG 4A: KẾT QUẢ ƯỚC LƯỢNG CRE QUA 4 TẦNG BIẾN KIỂM SOÁT (M1 - M4)",
  keep = c("(Intercept)", "iq_avg", culture_vars, controls_full)
)
## 
## ==============================================================================
## BẢNG 4A: KẾT QUẢ ƯỚC LƯỢNG CRE QUA 4 TẦNG BIẾN KIỂM SOÁT (M1 - M4) 
## Ghi chú: Hệ số ước lượng kèm sai số chuẩn (CLUSTER) trong ngoặc đơn.
## Mức ý nghĩa: * p < 0.10; ** p < 0.05; *** p < 0.01. Đã kiểm soát hiệu ứng năm.
## ==============================================================================
##  Variable                 M1_GDP_Pop           M2_Internet          M3_Finance_Trade     M4_Education_Full   
##  (Intercept)              -22.7402*** (4.8011) -23.9933*** (3.9925) -26.4692*** (3.7917) -27.4373*** (4.1206)
##  iq_avg                   0.0812 (0.2823)      0.0521 (0.2699)      0.0060 (0.2805)      0.0307 (0.2801)     
##  pdi                      0.0040 (0.0083)      0.0010 (0.0055)      -0.0028 (0.0056)     -0.0036 (0.0061)    
##  idv                      -0.0005 (0.0043)     -0.0042 (0.0047)     -0.0094** (0.0043)   -0.0119** (0.0052)  
##  mas                      0.0025 (0.0037)      0.0033 (0.0028)      0.0011 (0.0031)      0.0024 (0.0032)     
##  uai                      0.0044 (0.0046)      0.0054 (0.0042)      0.0049 (0.0039)      0.0036 (0.0036)     
##  lto                      0.0122** (0.0048)    0.0055 (0.0049)      0.0010 (0.0044)      0.0006 (0.0045)     
##  ivr                      -0.0032 (0.0062)     -0.0058 (0.0058)     -0.0091* (0.0048)    -0.0103* (0.0055)   
##  ln_gdppc                 1.6398*** (0.4092)   1.2161*** (0.3567)   1.2034*** (0.4232)   1.1367*** (0.4195)  
##  ln_population            0.6650 (0.8476)      0.4836 (0.8947)      0.5104 (0.8058)      0.4700 (0.8030)     
##  internet_users_pct                            0.0110** (0.0047)    0.0117*** (0.0044)   0.0123*** (0.0047)  
##  private_credit_pct_gdp                                             -0.0024 (0.0022)     -0.0022 (0.0022)    
##  trade_open_pct_gdp                                                 0.0019 (0.0029)      0.0017 (0.0029)     
##  secondary_enrollment_pct                                                                0.0049* (0.0029)    
##  Observations (N)         481                  481                  481                  481                 
##  Countries                37                   37                   37                   37
# In bảng tổng hợp riêng các biến chính (iq_avg và 6 chiều văn hoá)
nested_coefs <- do.call(rbind, lapply(names(nested_models), function(lbl) {
  collect_coefs(nested_models[[lbl]], lbl, "cluster", keep = c("iq_avg", culture_vars))
}))
cat("\n================ BẢNG 4B: CHI TIẾT HỆ SỐ THỂ CHẾ & VĂN HOÁ QUA M1 - M4 ================\n")
## 
## ================ BẢNG 4B: CHI TIẾT HỆ SỐ THỂ CHẾ & VĂN HOÁ QUA M1 - M4 ================
print(nested_coefs, digits = 4, row.names = FALSE)
##              model inference   N countries   term   estimate std_error statistic df p_value
##         M1_GDP_Pop   cluster 481        37 iq_avg  0.0811878  0.282302   0.28759 NA 0.77379
##         M1_GDP_Pop   cluster 481        37    pdi  0.0040213  0.008292   0.48499 NA 0.62792
##         M1_GDP_Pop   cluster 481        37    idv -0.0004845  0.004338  -0.11168 NA 0.91113
##         M1_GDP_Pop   cluster 481        37    mas  0.0025383  0.003692   0.68753 NA 0.49210
##         M1_GDP_Pop   cluster 481        37    uai  0.0044019  0.004614   0.95407 NA 0.34055
##         M1_GDP_Pop   cluster 481        37    lto  0.0121959  0.004840   2.51999 NA 0.01208
##         M1_GDP_Pop   cluster 481        37    ivr -0.0031921  0.006238  -0.51170 NA 0.60911
##        M2_Internet   cluster 481        37 iq_avg  0.0521153  0.269917   0.19308 NA 0.84698
##        M2_Internet   cluster 481        37    pdi  0.0010430  0.005452   0.19131 NA 0.84837
##        M2_Internet   cluster 481        37    idv -0.0042078  0.004743  -0.88717 NA 0.37545
##        M2_Internet   cluster 481        37    mas  0.0033279  0.002819   1.18070 NA 0.23834
##        M2_Internet   cluster 481        37    uai  0.0054023  0.004178   1.29315 NA 0.19662
##        M2_Internet   cluster 481        37    lto  0.0055064  0.004874   1.12975 NA 0.25918
##        M2_Internet   cluster 481        37    ivr -0.0057780  0.005804  -0.99556 NA 0.32000
##   M3_Finance_Trade   cluster 481        37 iq_avg  0.0060220  0.280510   0.02147 NA 0.98288
##   M3_Finance_Trade   cluster 481        37    pdi -0.0027960  0.005635  -0.49617 NA 0.62001
##   M3_Finance_Trade   cluster 481        37    idv -0.0094082  0.004275  -2.20067 NA 0.02827
##   M3_Finance_Trade   cluster 481        37    mas  0.0010901  0.003054   0.35689 NA 0.72134
##   M3_Finance_Trade   cluster 481        37    uai  0.0048554  0.003866   1.25586 NA 0.20982
##   M3_Finance_Trade   cluster 481        37    lto  0.0009800  0.004364   0.22458 NA 0.82241
##   M3_Finance_Trade   cluster 481        37    ivr -0.0090878  0.004786  -1.89869 NA 0.05825
##  M4_Education_Full   cluster 481        37 iq_avg  0.0306525  0.280092   0.10944 NA 0.91290
##  M4_Education_Full   cluster 481        37    pdi -0.0035597  0.006098  -0.58375 NA 0.55968
##  M4_Education_Full   cluster 481        37    idv -0.0118636  0.005211  -2.27682 NA 0.02327
##  M4_Education_Full   cluster 481        37    mas  0.0023906  0.003204   0.74606 NA 0.45602
##  M4_Education_Full   cluster 481        37    uai  0.0035679  0.003627   0.98383 NA 0.32573
##  M4_Education_Full   cluster 481        37    lto  0.0006345  0.004484   0.14150 NA 0.88754
##  M4_Education_Full   cluster 481        37    ivr -0.0102893  0.005498  -1.87154 NA 0.06192
# ==============================================================================
# BƯỚC 5: SO SÁNH POOLED OLS, FE, RE, CRE/MUNDLAK & KIỂM ĐỊNH H1 ====
# -> So sánh 4 phương pháp ước lượng dữ liệu bảng và kiểm định giả thuyết H1
#    (cả tác động trong nước within-country và tác động giữa các nước between-country).
# -> Cách chạy: Bôi đen toàn bộ Bước 5 và nhấn Ctrl + Enter.
# ==============================================================================

pool_full <- safe_call(fit_noncre(df, method = "pooling", with_culture = TRUE), "Pooled OLS")
fe_model  <- safe_call(fit_noncre(df, method = "within",  with_culture = FALSE), "Country FE")
re_model  <- safe_call(fit_noncre(df, method = "random",  with_culture = TRUE), "Random Effects")
cre_full  <- nested_models[["M4_Education_Full"]]

main_models <- list(
  Pooled_OLS     = pool_full,
  Country_FE     = fe_model,
  Random_Effects = re_model,
  CRE_Mundlak    = cre_full
)

# 5A. Bảng đối chiếu 4 mô hình chính (Pooled OLS, FE, RE, CRE)
print_model_table(
  main_models,
  heading = "BẢNG 5A: ĐỐI CHIẾU POOLED OLS, FIXED EFFECTS (FE), RANDOM EFFECTS (RE) & CRE/MUNDLAK",
  keep = c("(Intercept)", "iq_avg", culture_vars, controls_full, paste0(c("iq_avg", controls_full), "_m"))
)
## 
## ==============================================================================
## BẢNG 5A: ĐỐI CHIẾU POOLED OLS, FIXED EFFECTS (FE), RANDOM EFFECTS (RE) & CRE/MUNDLAK 
## Ghi chú: Hệ số ước lượng kèm sai số chuẩn (CLUSTER) trong ngoặc đơn.
## Mức ý nghĩa: * p < 0.10; ** p < 0.05; *** p < 0.01. Đã kiểm soát hiệu ứng năm.
## ==============================================================================
##  Variable                   Pooled_OLS           Country_FE         Random_Effects       CRE_Mundlak         
##  (Intercept)                -24.2747*** (3.8917)                    -22.2111*** (2.9968) -27.4373*** (4.1206)
##  iq_avg                     -0.1094 (0.5481)     0.0307 (0.2758)    0.0785 (0.2557)      0.0307 (0.2801)     
##  pdi                        0.0006 (0.0074)                         0.0005 (0.0080)      -0.0036 (0.0061)    
##  idv                        -0.0058 (0.0039)                        -0.0021 (0.0057)     -0.0119** (0.0052)  
##  mas                        0.0024 (0.0034)                         0.0026 (0.0041)      0.0024 (0.0032)     
##  uai                        0.0037 (0.0037)                         0.0033 (0.0059)      0.0036 (0.0036)     
##  lto                        0.0076* (0.0042)                        0.0121* (0.0066)     0.0006 (0.0045)     
##  ivr                        -0.0061 (0.0056)                        -0.0025 (0.0061)     -0.0103* (0.0055)   
##  ln_gdppc                   1.3515*** (0.4753)   1.1367*** (0.4130) 1.3505*** (0.3487)   1.1367*** (0.4195)  
##  ln_population              1.1200*** (0.0807)   0.4700 (0.7908)    1.0617*** (0.1149)   0.4700 (0.8030)     
##  internet_users_pct         0.0404*** (0.0114)   0.0123*** (0.0046) 0.0120** (0.0047)    0.0123*** (0.0047)  
##  private_credit_pct_gdp     -0.0040* (0.0023)    -0.0022 (0.0022)   -0.0024 (0.0020)     -0.0022 (0.0022)    
##  trade_open_pct_gdp         0.0014 (0.0017)      0.0017 (0.0028)    0.0013 (0.0024)      0.0017 (0.0029)     
##  secondary_enrollment_pct   0.0045 (0.0056)      0.0049* (0.0029)   0.0047* (0.0028)     0.0049* (0.0029)    
##  iq_avg_m                                                                                -0.6472 (0.6548)    
##  ln_gdppc_m                                                                              -0.0954 (0.4749)    
##  ln_population_m                                                                         0.7555 (0.8000)     
##  internet_users_pct_m                                                                    0.0958*** (0.0352)  
##  private_credit_pct_gdp_m                                                                -0.0053 (0.0034)    
##  trade_open_pct_gdp_m                                                                    0.0010 (0.0034)     
##  secondary_enrollment_pct_m                                                              0.0032 (0.0072)     
##  Observations (N)           481                  481                481                  481                 
##  Countries                  37                   37                 37                   37
# 5B. Kết quả chi tiết mô hình CRE đầy đủ với sai số chuẩn cụm (HC1) và CR2 Satterthwaite
main_cluster <- get_coefs(cre_full, "cluster")
main_cr2     <- get_coefs(cre_full, "cr2")

cat("\n================ BẢNG 5B: MÔ HÌNH CHÍNH CRE - SAI SỐ CHUẨN CỤM QUỐC GIA (HC1) ================\n")
## 
## ================ BẢNG 5B: MÔ HÌNH CHÍNH CRE - SAI SỐ CHUẨN CỤM QUỐC GIA (HC1) ================
print(main_cluster[!grepl("^factor\\(year\\)", main_cluster$term), ], digits = 4, row.names = FALSE)
##                        term    estimate std_error statistic df   p_value
##                 (Intercept) -27.4373410  4.120612   -6.6586 NA 8.112e-11
##                      iq_avg   0.0306525  0.280092    0.1094 NA 9.129e-01
##                         pdi  -0.0035597  0.006098   -0.5838 NA 5.597e-01
##                         idv  -0.0118636  0.005211   -2.2768 NA 2.327e-02
##                         mas   0.0023906  0.003204    0.7461 NA 4.560e-01
##                         uai   0.0035679  0.003627    0.9838 NA 3.257e-01
##                         lto   0.0006345  0.004484    0.1415 NA 8.875e-01
##                         ivr  -0.0102893  0.005498   -1.8715 NA 6.192e-02
##                    ln_gdppc   1.1366774  0.419451    2.7099 NA 6.988e-03
##               ln_population   0.4699575  0.803016    0.5852 NA 5.587e-01
##          internet_users_pct   0.0122864  0.004652    2.6410 NA 8.556e-03
##      private_credit_pct_gdp  -0.0022078  0.002188   -1.0089 NA 3.136e-01
##          trade_open_pct_gdp   0.0016669  0.002866    0.5815 NA 5.612e-01
##    secondary_enrollment_pct   0.0048980  0.002948    1.6613 NA 9.736e-02
##                    iq_avg_m  -0.6472420  0.654794   -0.9885 NA 3.235e-01
##                  ln_gdppc_m  -0.0953957  0.474862   -0.2009 NA 8.409e-01
##             ln_population_m   0.7554798  0.800030    0.9443 NA 3.455e-01
##        internet_users_pct_m   0.0957848  0.035190    2.7219 NA 6.743e-03
##    private_credit_pct_gdp_m  -0.0053033  0.003422   -1.5496 NA 1.219e-01
##        trade_open_pct_gdp_m   0.0010400  0.003372    0.3085 NA 7.579e-01
##  secondary_enrollment_pct_m   0.0032321  0.007171    0.4507 NA 6.524e-01
cat("\n================ BẢNG 5C: MÔ HÌNH CHÍNH CRE - SAI SỐ CHUẨN CR2 SATTERTHWAITE ================\n")
## 
## ================ BẢNG 5C: MÔ HÌNH CHÍNH CRE - SAI SỐ CHUẨN CR2 SATTERTHWAITE ================
cat("(Khuyến nghị: Dùng cột p_value của bảng CR2 này để kết luận cho các biến văn hoá)\n")
## (Khuyến nghị: Dùng cột p_value của bảng CR2 này để kết luận cho các biến văn hoá)
print(main_cr2[!grepl("^factor\\(year\\)", main_cr2$term), ], digits = 4, row.names = FALSE)
##                        term    estimate std_error statistic     df   p_value
##                 (Intercept) -27.4373410  5.639475  -4.86523  8.863 0.0009297
##                      iq_avg   0.0306525  0.310009   0.09888 16.427 0.9224331
##                         pdi  -0.0035597  0.008050  -0.44219  7.951 0.6701334
##                         idv  -0.0118636  0.006881  -1.72406  8.503 0.1207518
##                         mas   0.0023906  0.004027   0.59358  7.902 0.5693905
##                         uai   0.0035679  0.004689   0.76090 11.534 0.4619919
##                         lto   0.0006345  0.005962   0.10643 10.672 0.9172124
##                         ivr  -0.0102893  0.007376  -1.39492 10.445 0.1919921
##                    ln_gdppc   1.1366774  0.479583   2.37014 12.501 0.0346270
##               ln_population   0.4699575  0.905670   0.51891  8.409 0.6172031
##          internet_users_pct   0.0122864  0.005142   2.38952  7.103 0.0476983
##      private_credit_pct_gdp  -0.0022078  0.002460  -0.89729 12.783 0.3861497
##          trade_open_pct_gdp   0.0016669  0.003362   0.49580  7.779 0.6337353
##    secondary_enrollment_pct   0.0048980  0.003129   1.56523  7.200 0.1603237
##                    iq_avg_m  -0.6472420  0.866641  -0.74684 12.003 0.4695370
##                  ln_gdppc_m  -0.0953957  0.581798  -0.16397 14.262 0.8720581
##             ln_population_m   0.7554798  0.896454   0.84274  9.267 0.4205899
##        internet_users_pct_m   0.0957848  0.047249   2.02723  9.423 0.0718532
##    private_credit_pct_gdp_m  -0.0053033  0.004331  -1.22454 10.489 0.2475390
##        trade_open_pct_gdp_m   0.0010400  0.003927   0.26482 11.682 0.7957639
##  secondary_enrollment_pct_m   0.0032321  0.009112   0.35472  7.017 0.7332199
# 5C. [FIX 4] Tách bạch tác động Trong nước (Within) và Giữa các nước (Between) của Thể chế (H1)
institution_effects <- function(m, inst = "iq_avg") {
  if (is.null(m)) return(NULL)
  b <- stats::coef(m)
  im <- paste0(inst, "_m")
  if (!all(c(inst, im) %in% names(b))) return(NULL)
  V1 <- vcov_country(m)
  V2 <- as.matrix(clubSandwich::vcovCR(m, cluster = "individual", type = "CR2"))
  one <- function(w, label) {
    est <- sum(w * b[names(w)])
    se1 <- sqrt(as.numeric(t(w) %*% V1[names(w), names(w)] %*% w))
    se2 <- sqrt(as.numeric(t(w) %*% V2[names(w), names(w)] %*% w))
    data.frame(
      effect = label, estimate = est, clustered_se = se1,
      clustered_p = 2 * stats::pnorm(-abs(est / se1)),
      CR2_se = se2, CR2_p_normal = 2 * stats::pnorm(-abs(est / se2))
    )
  }
  rbind(
    one(stats::setNames(1, inst), "Within-country (Tác động thay đổi theo thời gian = FE)"),
    one(stats::setNames(c(1, 1), c(inst, im)), "Between-country (Chênh lệch mức thể chế giữa các nước)")
  )
}

inst_effects <- safe_call(institution_effects(cre_full), "Within/between institution effect")
cat("\n================ BẢNG 5D [FIX 4]: TÁC ĐỘNG TRONG NƯỚC VS GIỮA CÁC NƯỚC CỦA THỂ CHẾ (H1) ================\n")
## 
## ================ BẢNG 5D [FIX 4]: TÁC ĐỘNG TRONG NƯỚC VS GIỮA CÁC NƯỚC CỦA THỂ CHẾ (H1) ================
print(inst_effects, digits = 4, row.names = FALSE)
##                                                  effect estimate clustered_se clustered_p CR2_se CR2_p_normal
##  Within-country (Tác động thay đổi theo thời gian = FE)  0.03065       0.2801      0.9129 0.3100       0.9212
##  Between-country (Chênh lệch mức thể chế giữa các nước) -0.61659       0.6357      0.3321 0.8499       0.4682
# ==============================================================================
# BƯỚC 6: KIỂM ĐỊNH LỰA CHỌN MÔ HÌNH, KHUYẾT TẬT & ĐỘ NHẠY SAI SỐ CHUẨN ====
# -> Kiểm định F, Breusch-Pagan LM, Hausman, Wald cho các biến trung bình Mundlak,
#    tự tương quan (Breusch-Godfrey), phụ thuộc chéo (Pesaran CD), phương sai
#    thay đổi (Breusch-Pagan) và so sánh 4 phương pháp tính sai số chuẩn.
# -> Cách chạy: Bôi đen toàn bộ Bước 6 và nhấn Ctrl + Enter.
# ==============================================================================

pool_common <- safe_call(fit_noncre(df, "pooling", with_culture = FALSE), "Pooled common")
re_common   <- safe_call(fit_noncre(df, "random",  with_culture = FALSE), "RE common")

post_tests <- list()
post_tests[["FE_vs_Pooled_F"]]  <- safe_call(plm::pFtest(fe_model, pool_common), "F test: FE vs pooled")
post_tests[["RE_vs_Pooled_LM"]] <- safe_call(plm::plmtest(pool_common, effect = "individual", type = "bp"), "Breusch-Pagan LM")
post_tests[["FE_vs_RE_Hausman"]] <- safe_call(plm::phtest(fe_model, re_common), "Hausman test")
post_tests[["FE_Breusch_Godfrey_serial"]] <- safe_call(plm::pbgtest(fe_model), "Breusch-Godfrey serial correlation")
post_tests[["FE_Pesaran_CD"]] <- safe_call(plm::pcdtest(fe_model, test = "cd"), "Pesaran CD")

pooled_lm_for_bp <- stats::lm(make_formula(culture = character(), add_mundlak = FALSE), data = df)
post_tests[["Pooled_Breusch_Pagan_heteroskedasticity"]] <- safe_call(
  lmtest::bptest(pooled_lm_for_bp), "Breusch-Pagan heteroskedasticity"
)

# Kiểm định Wald vững theo cụm quốc gia cho 7 biến trung bình Mundlak (_m = 0)
wald_mundlak <- function(m, means) {
  if (is.null(m)) return(NULL)
  b <- stats::coef(m)
  if (!all(means %in% names(b))) {
    stop("Không ước lượng được đầy đủ các biến trung bình Mundlak: ",
         paste(setdiff(means, names(b)), collapse = ", "))
  }
  V <- vcov_country(m)
  b0 <- b[means]
  V0 <- V[means, means, drop = FALSE]
  stat <- as.numeric(crossprod(b0, solve(V0, b0)))
  list(statistic = stat, df = length(means),
       p_value = stats::pchisq(stat, df = length(means), lower.tail = FALSE))
}

mean_terms <- paste0(c("iq_avg", controls_full), "_m")
mundlak_test <- safe_call(wald_mundlak(cre_full, mean_terms), "Robust joint Wald test of Mundlak means")

post_test_table <- do.call(rbind, lapply(names(post_tests), function(label) {
  test <- post_tests[[label]]
  if (is.null(test)) return(data.frame(
    test = label, statistic = NA_real_, df = NA_character_, p_value = NA_real_,
    method = "TEST FAILED", stringsAsFactors = FALSE
  ))
  data.frame(
    test = label, statistic = unname(as.numeric(test$statistic[1])),
    df = paste(test$parameter, collapse = ", "),
    p_value = test$p.value, method = test$method
  )
}))

if (!is.null(mundlak_test)) {
  post_test_table <- rbind(post_test_table, data.frame(
    test = "Mundlak_means_joint_cluster_robust_Wald",
    statistic = mundlak_test$statistic,
    df = as.character(mundlak_test$df), p_value = mundlak_test$p_value,
    method = "Country-clustered HC1 Wald chi-square (7 biến trung bình Mundlak đồng thời = 0)"
  ))
}

cat("\n================ BẢNG 6A: KIỂM ĐỊNH CHỌN MÔ HÌNH & KHUYẾT TẬT ================\n")
## 
## ================ BẢNG 6A: KIỂM ĐỊNH CHỌN MÔ HÌNH & KHUYẾT TẬT ================
print(post_test_table, digits = 4, row.names = FALSE)
##                                     test statistic      df    p_value
##                           FE_vs_Pooled_F   103.537 36, 425 1.481e-186
##                          RE_vs_Pooled_LM  1895.745       1  0.000e+00
##                         FE_vs_RE_Hausman     1.432      19  1.000e+00
##                FE_Breusch_Godfrey_serial   205.649      13  9.437e-37
##                            FE_Pesaran_CD    -1.537          1.243e-01
##  Pooled_Breusch_Pagan_heteroskedasticity   126.313      19  7.245e-18
##  Mundlak_means_joint_cluster_robust_Wald    10.662       7  1.541e-01
##                                                                           method
##                                                    F test for individual effects
##                                      Lagrange Multiplier Test -  (Breusch-Pagan)
##                                                                     Hausman Test
##           Breusch-Godfrey/Wooldridge test for serial correlation in panel models
##                        Pesaran CD test for  cross-sectional dependence in panels
##                                                   studentized Breusch-Pagan test
##  Country-clustered HC1 Wald chi-square (7 biến trung bình Mundlak đồng thời = 0)
cat("\n[Lưu ý giải thích]:\n",
    "- Kiểm định Hausman cổ điển không vững khi có tự tương quan và phương sai thay đổi -> chỉ dùng tham khảo.\n",
    "- Hãy dựa vào kiểm định 'Mundlak_means_joint_cluster_robust_Wald' (đã vững theo cụm quốc gia).\n",
    "- Tự tương quan (Breusch-Godfrey) và phương sai thay đổi (Breusch-Pagan) đều có p < 0.001,\n",
    "  do đó việc sử dụng sai số chuẩn cụm theo quốc gia (HC1 / CR2) là hoàn toàn bắt buộc.\n", sep = "")
## 
## [Lưu ý giải thích]:
## - Kiểm định Hausman cổ điển không vững khi có tự tương quan và phương sai thay đổi -> chỉ dùng tham khảo.
## - Hãy dựa vào kiểm định 'Mundlak_means_joint_cluster_robust_Wald' (đã vững theo cụm quốc gia).
## - Tự tương quan (Breusch-Godfrey) và phương sai thay đổi (Breusch-Pagan) đều có p < 0.001,
##   do đó việc sử dụng sai số chuẩn cụm theo quốc gia (HC1 / CR2) là hoàn toàn bắt buộc.
# 6B. Độ nhạy của sai số chuẩn (HC1 cluster, CR2, Driscoll-Kraay, Double clustering)
se_sensitivity <- do.call(rbind, lapply(
  list(FE = fe_model, CRE = cre_full), function(m) {
    if (is.null(m)) return(NULL)
    do.call(rbind, lapply(c("cluster", "cr2", "dk", "double"), function(inf) {
      collect_coefs(m, model_label = if (identical(m, fe_model)) "FE" else "CRE",
                    inference = inf, keep = c("iq_avg", culture_vars))
    }))
  }
))
## Warning in sqrt(diag(se)): NaNs produced
## Warning in sqrt(diag(se)): NaNs produced
cat("\n================ BẢNG 6B: ĐỘ NHẠY SAI SỐ CHUẨN (CLUSTER HC1 / CR2 / DK / DOUBLE) ================\n")
## 
## ================ BẢNG 6B: ĐỘ NHẠY SAI SỐ CHUẨN (CLUSTER HC1 / CR2 / DK / DOUBLE) ================
cat("(Lưu ý: Không dùng dk và double cho biến văn hoá bất biến theo thời gian khi T = 13)\n")
## (Lưu ý: Không dùng dk và double cho biến văn hoá bất biến theo thời gian khi T = 13)
print(se_sensitivity, digits = 4, row.names = FALSE)
##  model inference   N countries   term   estimate std_error statistic     df   p_value
##     FE   cluster 481        37 iq_avg  0.0306525 0.2758152   0.11113     NA 9.116e-01
##     FE       cr2 481        37 iq_avg  0.0306525 0.3100090   0.09888 16.427 9.224e-01
##     FE        dk 481        37 iq_avg  0.0306525 0.0797103   0.38455     NA 7.008e-01
##     FE    double 481        37 iq_avg  0.0306525 0.2549579   0.12023     NA 9.044e-01
##    CRE   cluster 481        37 iq_avg  0.0306525 0.2800917   0.10944     NA 9.129e-01
##    CRE   cluster 481        37    pdi -0.0035597 0.0060980  -0.58375     NA 5.597e-01
##    CRE   cluster 481        37    idv -0.0118636 0.0052106  -2.27682     NA 2.327e-02
##    CRE   cluster 481        37    mas  0.0023906 0.0032043   0.74606     NA 4.560e-01
##    CRE   cluster 481        37    uai  0.0035679 0.0036266   0.98383     NA 3.257e-01
##    CRE   cluster 481        37    lto  0.0006345 0.0044844   0.14150     NA 8.875e-01
##    CRE   cluster 481        37    ivr -0.0102893 0.0054978  -1.87154     NA 6.192e-02
##    CRE       cr2 481        37 iq_avg  0.0306525 0.3100090   0.09888 16.427 9.224e-01
##    CRE       cr2 481        37    pdi -0.0035597 0.0080502  -0.44219  7.951 6.701e-01
##    CRE       cr2 481        37    idv -0.0118636 0.0068812  -1.72406  8.503 1.208e-01
##    CRE       cr2 481        37    mas  0.0023906 0.0040274   0.59358  7.902 5.694e-01
##    CRE       cr2 481        37    uai  0.0035679 0.0046891   0.76090 11.534 4.620e-01
##    CRE       cr2 481        37    lto  0.0006345 0.0059617   0.10643 10.672 9.172e-01
##    CRE       cr2 481        37    ivr -0.0102893 0.0073762  -1.39492 10.445 1.920e-01
##    CRE        dk 481        37 iq_avg  0.0306525 0.1053164   0.29105     NA 7.711e-01
##    CRE        dk 481        37    pdi -0.0035597 0.0073165  -0.48654     NA 6.268e-01
##    CRE        dk 481        37    idv -0.0118636 0.0097528  -1.21643     NA 2.245e-01
##    CRE        dk 481        37    mas  0.0023906 0.0086819   0.27535     NA 7.832e-01
##    CRE        dk 481        37    uai  0.0035679 0.0063302   0.56364     NA 5.733e-01
##    CRE        dk 481        37    lto  0.0006345 0.0047186   0.13447     NA 8.931e-01
##    CRE        dk 481        37    ivr -0.0102893 0.0093857  -1.09627     NA 2.735e-01
##    CRE    double 481        37 iq_avg  0.0306525 0.2630111   0.11654     NA 9.073e-01
##    CRE    double 481        37    pdi -0.0035597 0.0003154 -11.28586     NA 3.616e-26
##    CRE    double 481        37    idv -0.0118636       NaN       NaN     NA       NaN
##    CRE    double 481        37    mas  0.0023906 0.0043954   0.54389     NA 5.868e-01
##    CRE    double 481        37    uai  0.0035679 0.0012291   2.90283     NA 3.881e-03
##    CRE    double 481        37    lto  0.0006345 0.0011663   0.54404     NA 5.867e-01
##    CRE    double 481        37    ivr -0.0102893 0.0052397  -1.96371     NA 5.018e-02
# ==============================================================================
# BƯỚC 7: KIỂM ĐỊNH GIẢ THUYẾT VĂN HOÁ H2a - H2f (TỪNG CHIỀU RIÊNG LẺ) ====
# -> Chạy 6 mô hình CRE riêng cho từng chiều văn hoá Hofstede (PDI, IDV, MAS,
#    UAI, LTO, IVR) và kiểm định với p-value CR2 cùng hiệu chỉnh đa kiểm định Holm [FIX 3].
# -> Cách chạy: Bôi đen toàn bộ Bước 7 và nhấn Ctrl + Enter.
# ==============================================================================

culture_models <- lapply(culture_vars, function(v) {
  safe_call(fit_cre(df, culture = v), paste0("Culture dimension: ", v))
})
names(culture_models) <- culture_vars

# 7A. Bảng so sánh 6 mô hình văn hoá riêng lẻ
print_model_table(
  culture_models,
  heading = "BẢNG 7A: KẾT QUẢ 6 MÔ HÌNH CRE RIÊNG CHO TỪNG CHIỀU VĂN HOÁ HOFSTEDE (H2a - H2f)",
  keep = c("(Intercept)", "iq_avg", culture_vars, controls_full)
)
## 
## ==============================================================================
## BẢNG 7A: KẾT QUẢ 6 MÔ HÌNH CRE RIÊNG CHO TỪNG CHIỀU VĂN HOÁ HOFSTEDE (H2a - H2f) 
## Ghi chú: Hệ số ước lượng kèm sai số chuẩn (CLUSTER) trong ngoặc đơn.
## Mức ý nghĩa: * p < 0.10; ** p < 0.05; *** p < 0.01. Đã kiểm soát hiệu ứng năm.
## ==============================================================================
##  Variable                 pdi                  idv                  mas                  uai                 
##  (Intercept)              -24.4982*** (4.0969) -25.8216*** (4.2083) -24.1770*** (4.3964) -24.8924*** (4.0227)
##  iq_avg                   0.0307 (0.2785)      0.0307 (0.2785)      0.0307 (0.2785)      0.0307 (0.2785)     
##  pdi                      0.0021 (0.0056)                                                                    
##  idv                                           -0.0127** (0.0054)                                            
##  mas                                                                0.0010 (0.0041)                          
##  uai                                                                                     0.0088* (0.0045)    
##  lto                                                                                                         
##  ivr                                                                                                         
##  ln_gdppc                 1.1367*** (0.4171)   1.1367*** (0.4171)   1.1367*** (0.4171)   1.1367*** (0.4171)  
##  ln_population            0.4700 (0.7986)      0.4700 (0.7986)      0.4700 (0.7986)      0.4700 (0.7986)     
##  internet_users_pct       0.0123*** (0.0046)   0.0123*** (0.0046)   0.0123*** (0.0046)   0.0123*** (0.0046)  
##  private_credit_pct_gdp   -0.0022 (0.0022)     -0.0022 (0.0022)     -0.0022 (0.0022)     -0.0022 (0.0022)    
##  trade_open_pct_gdp       0.0017 (0.0029)      0.0017 (0.0029)      0.0017 (0.0029)      0.0017 (0.0029)     
##  secondary_enrollment_pct 0.0049* (0.0029)     0.0049* (0.0029)     0.0049* (0.0029)     0.0049* (0.0029)    
##  Observations (N)         481                  481                  481                  481                 
##  Countries                37                   37                   37                   37                  
##  lto                  ivr                 
##  -24.5428*** (4.1640) -26.8947*** (4.3423)
##  0.0307 (0.2785)      0.0307 (0.2785)     
##                                           
##                                           
##                                           
##                                           
##  0.0097*** (0.0037)                       
##                       -0.0126*** (0.0044) 
##  1.1367*** (0.4171)   1.1367*** (0.4171)  
##  0.4700 (0.7986)      0.4700 (0.7986)     
##  0.0123*** (0.0046)   0.0123*** (0.0046)  
##  -0.0022 (0.0022)     -0.0022 (0.0022)    
##  0.0017 (0.0029)      0.0017 (0.0029)     
##  0.0049* (0.0029)     0.0049* (0.0029)    
##  481                  481                 
##  37                   37
# 7B. Bảng tổng hợp kiểm định giả thuyết H2a - H2f kèm hiệu chỉnh Holm [FIX 3]
expected_sign <- c(pdi = -1, idv = 1, mas = -1, uai = -1, lto = 1, ivr = 1)
hypothesis_label <- setNames(paste0("H2", letters[1:6]), culture_vars)

culture_results <- do.call(rbind, lapply(culture_vars, function(v) {
  m <- culture_models[[v]]
  cluster <- get_coefs(m, "cluster")
  cr2 <- get_coefs(m, "cr2")
  a <- cluster[cluster$term == v, , drop = FALSE]
  b <- cr2[cr2$term == v, , drop = FALSE]
  p2 <- if (nrow(b)) b$p_value[1] else NA_real_
  support <- if (!is.finite(p2)) "CR2 unavailable"
    else if (p2 < .05 && sign(a$estimate[1]) == expected_sign[[v]])
      "Đúng dấu & CR2 p < 0.05 (trước Holm)"
    else "Không đạt ý nghĩa ở mức CR2 p < 0.05"
  data.frame(
    hypothesis         = hypothesis_label[[v]],
    variable           = v,
    expected_direction = ifelse(expected_sign[[v]] > 0, "+", "-"),
    beta               = a$estimate[1],
    clustered_se       = a$std_error[1],
    clustered_p        = a$p_value[1],
    CR2_se             = if (nrow(b)) b$std_error[1] else NA_real_,
    CR2_df             = if (nrow(b)) b$df[1] else NA_real_,
    CR2_p              = p2,
    preliminary_result = support
  )
}))

culture_results$CR2_p_holm <- stats::p.adjust(culture_results$CR2_p, method = "holm")
culture_results$result_after_holm <- ifelse(
  is.finite(culture_results$CR2_p_holm) & culture_results$CR2_p_holm < .05 &
    ((culture_results$beta > 0 & culture_results$expected_direction == "+") |
     (culture_results$beta < 0 & culture_results$expected_direction == "-")),
  "Ủng hộ sau hiệu chỉnh Holm", "Không ủng hộ sau hiệu chỉnh Holm"
)

cat("\n================ BẢNG 7B [FIX 3]: TỔNG HỢP KIỂM ĐỊNH GIẢ THUYẾT H2a - H2f ================\n")
## 
## ================ BẢNG 7B [FIX 3]: TỔNG HỢP KIỂM ĐỊNH GIẢ THUYẾT H2a - H2f ================
print(culture_results, digits = 4, row.names = FALSE)
##  hypothesis variable expected_direction      beta clustered_se clustered_p   CR2_se CR2_df   CR2_p
##         H2a      pdi                  -  0.002090     0.005588    0.708495 0.006467 10.463 0.75288
##         H2b      idv                  + -0.012688     0.005355    0.018232 0.006343 11.419 0.06981
##         H2c      mas                  -  0.001040     0.004082    0.798940 0.004599  9.416 0.82585
##         H2d      uai                  -  0.008756     0.004538    0.054269 0.005553 13.385 0.13816
##         H2e      lto                  +  0.009712     0.003654    0.008148 0.004285 12.398 0.04204
##         H2f      ivr                  + -0.012631     0.004403    0.004317 0.005288 11.962 0.03427
##                    preliminary_result CR2_p_holm                result_after_holm
##  Không đạt ý nghĩa ở mức CR2 p < 0.05     1.0000 Không ủng hộ sau hiệu chỉnh Holm
##  Không đạt ý nghĩa ở mức CR2 p < 0.05     0.2793 Không ủng hộ sau hiệu chỉnh Holm
##  Không đạt ý nghĩa ở mức CR2 p < 0.05     1.0000 Không ủng hộ sau hiệu chỉnh Holm
##  Không đạt ý nghĩa ở mức CR2 p < 0.05     0.4145 Không ủng hộ sau hiệu chỉnh Holm
##  Đúng dấu & CR2 p < 0.05 (trước Holm)     0.2102 Không ủng hộ sau hiệu chỉnh Holm
##  Không đạt ý nghĩa ở mức CR2 p < 0.05     0.2056 Không ủng hộ sau hiệu chỉnh Holm
# ==============================================================================
# BƯỚC 8: PHÂN TÍCH SÁU THÀNH PHẦN THỂ CHẾ WGI (VA, PV, GE, RQ, RL, CC) ====
# -> Thay chỉ số tổng hợp iq_avg bằng từng cấu phần WGI để xem khía cạnh thể chế
#    nào có vai trò nổi bật nhất (tính lại trung bình Mundlak cho từng thành phần).
# -> Cách chạy: Bôi đen toàn bộ Bước 8 và nhấn Ctrl + Enter.
# ==============================================================================

wgi_models <- lapply(wgi_vars, function(v) {
  safe_call(fit_cre(df, institution = v, culture = culture_vars),
            paste0("WGI component: ", v))
})
names(wgi_models) <- wgi_vars

print_model_table(
  wgi_models,
  heading = "BẢNG 8A: KẾT QUẢ CRE KHI THAY IQ_AVG BẰNG TỪNG THÀNH PHẦN WGI (VA, PV, GE, RQ, RL, CC)",
  keep = c(wgi_vars, culture_vars, controls_full)
)
## 
## ==============================================================================
## BẢNG 8A: KẾT QUẢ CRE KHI THAY IQ_AVG BẰNG TỪNG THÀNH PHẦN WGI (VA, PV, GE, RQ, RL, CC) 
## Ghi chú: Hệ số ước lượng kèm sai số chuẩn (CLUSTER) trong ngoặc đơn.
## Mức ý nghĩa: * p < 0.10; ** p < 0.05; *** p < 0.01. Đã kiểm soát hiệu ứng năm.
## ==============================================================================
##  Variable                 va                pv                 ge                 rq                 rl                
##  va                       -0.2628 (0.1821)                                                                             
##  pv                                         0.0720 (0.1277)                                                            
##  ge                                                            0.0439 (0.1632)                                         
##  rq                                                                               0.3087* (0.1772)                     
##  rl                                                                                                  0.0608 (0.1998)   
##  cc                                                                                                                    
##  pdi                      -0.0027 (0.0051)  -0.0015 (0.0052)   -0.0026 (0.0058)   -0.0035 (0.0059)   -0.0039 (0.0068)  
##  idv                      -0.0065* (0.0035) -0.0100* (0.0052)  -0.0131** (0.0064) -0.0123** (0.0055) -0.0119** (0.0053)
##  mas                      0.0023 (0.0033)   0.0000 (0.0044)    0.0017 (0.0035)    0.0026 (0.0033)    0.0020 (0.0033)   
##  uai                      0.0092* (0.0049)  0.0068 (0.0045)    0.0031 (0.0034)    0.0025 (0.0035)    0.0047 (0.0040)   
##  lto                      -0.0004 (0.0041)  0.0017 (0.0045)    0.0019 (0.0046)    0.0003 (0.0045)    0.0008 (0.0045)   
##  ivr                      -0.0080* (0.0045) 0.0006 (0.0074)    -0.0078 (0.0051)   -0.0088* (0.0050)  -0.0097* (0.0058) 
##  ln_gdppc                 1.1645** (0.4569) 1.1258*** (0.4204) 1.1201*** (0.4089) 1.1210*** (0.3941) 1.1240*** (0.4148)
##  ln_population            0.5570 (0.7536)   0.4676 (0.7362)    0.4947 (0.8070)    0.7337 (0.7511)    0.5010 (0.7862)   
##  internet_users_pct       0.0114** (0.0048) 0.0114** (0.0044)  0.0124*** (0.0046) 0.0125*** (0.0045) 0.0124*** (0.0046)
##  private_credit_pct_gdp   -0.0028 (0.0022)  -0.0021 (0.0022)   -0.0022 (0.0022)   -0.0022 (0.0021)   -0.0022 (0.0022)  
##  trade_open_pct_gdp       0.0020 (0.0028)   0.0016 (0.0029)    0.0017 (0.0028)    0.0013 (0.0026)    0.0017 (0.0029)   
##  secondary_enrollment_pct 0.0042 (0.0029)   0.0049* (0.0029)   0.0049* (0.0029)   0.0054* (0.0029)   0.0050* (0.0029)  
##  Observations (N)         481               481                481                481                481               
##  Countries                37                37                 37                 37                 37                
##  cc                
##                    
##                    
##                    
##                    
##                    
##  -0.0793 (0.1842)  
##  -0.0042 (0.0062)  
##  -0.0120** (0.0054)
##  0.0017 (0.0034)   
##  0.0019 (0.0035)   
##  0.0006 (0.0046)   
##  -0.0100* (0.0052) 
##  1.1620*** (0.4370)
##  0.3857 (0.7793)   
##  0.0122*** (0.0046)
##  -0.0022 (0.0022)  
##  0.0016 (0.0030)   
##  0.0049* (0.0029)  
##  481               
##  37
wgi_results_cr2 <- do.call(rbind, lapply(wgi_vars, function(v) {
  collect_coefs(wgi_models[[v]], paste0("WGI_", v), "cr2", keep = v)
}))
cat("\n================ BẢNG 8B: CHI TIẾT 6 THÀNH PHẦN WGI THEO SAI SỐ CHUẨN CR2 ================\n")
## 
## ================ BẢNG 8B: CHI TIẾT 6 THÀNH PHẦN WGI THEO SAI SỐ CHUẨN CR2 ================
print(wgi_results_cr2, digits = 4, row.names = FALSE)
##   model inference   N countries term estimate std_error statistic     df p_value
##  WGI_va       cr2 481        37   va -0.26277    0.2001   -1.3131  9.568  0.2198
##  WGI_pv       cr2 481        37   pv  0.07197    0.1371    0.5248 16.730  0.6066
##  WGI_ge       cr2 481        37   ge  0.04389    0.1809    0.2427 20.313  0.8107
##  WGI_rq       cr2 481        37   rq  0.30869    0.1916    1.6108 21.279  0.1220
##  WGI_rl       cr2 481        37   rl  0.06077    0.2220    0.2737 13.086  0.7886
##  WGI_cc       cr2 481        37   cc -0.07926    0.1980   -0.4003 22.207  0.6927
# ==============================================================================
# BƯỚC 9: HỆ SỐ CHUẨN HOÁ & DIỄN GIẢI Ý NGHĨA KINH TẾ [FIX 5] ====
# -> Tính hệ số chuẩn hoá (Standardized Beta) và mức thay đổi % của doanh số TMĐT
#    khi biến độc lập thay đổi 1 độ lệch chuẩn trong nước (within-country SD)
#    hoặc 1 đơn vị đo lường thực tế (+1 điểm WGI, +10 điểm Hofstede, +1 điểm %).
# -> Cách chạy: Bôi đen toàn bộ Bước 9 và nhấn Ctrl + Enter.
# ==============================================================================

if (!is.null(cre_full)) {
  source_coefs <- get_coefs(cre_full, "cluster")
  substantive <- c("iq_avg", culture_vars, controls_full)
  source_coefs <- source_coefs[source_coefs$term %in% substantive, , drop = FALSE]
  source_coefs$sd_x <- vapply(source_coefs$term, function(v) stats::sd(df[[v]]), numeric(1))
  source_coefs$sd_y <- stats::sd(df$ln_ecom)
  source_coefs$beta_standardized <- source_coefs$estimate * source_coefs$sd_x / source_coefs$sd_y

  # [FIX 5] Độ lệch chuẩn trong từng quốc gia (Within-country SD) cho các biến thay đổi theo thời gian
  within_sd <- function(v) stats::sd(df[[v]] - stats::ave(df[[v]], df$iso3))
  source_coefs$sd_x_within <- vapply(source_coefs$term, function(v) {
    if (v %in% culture_vars) NA_real_ else within_sd(v)
  }, numeric(1))
  source_coefs$ecom_pct_change_per_within_sd <- 100 *
    (exp(source_coefs$estimate * source_coefs$sd_x_within) - 1)

  source_coefs$change_in_x <- ifelse(source_coefs$term %in% culture_vars, 10, 1)
  source_coefs$ecom_percent_change <- 100 *
    (exp(source_coefs$estimate * source_coefs$change_in_x) - 1)
  source_coefs$interpretation_unit <- ifelse(
    source_coefs$term %in% culture_vars, "+10 điểm Hofstede",
    ifelse(source_coefs$term %in% c("ln_gdppc", "ln_population"),
           "+1 đơn vị log (Độ co giãn = estimate)",
           ifelse(source_coefs$term %in% c("internet_users_pct",
                                           "private_credit_pct_gdp",
                                           "trade_open_pct_gdp",
                                           "secondary_enrollment_pct"),
                  "+1 điểm phần trăm (%)", "+1 đơn vị WGI"))
  )

  cat("\n================ BẢNG 9: HỆ SỐ CHUẨN HOÁ & Ý NGHĨA KINH TẾ (MÔ HÌNH CRE CHÍNH) ================\n")
  print(source_coefs[, c("term", "estimate", "beta_standardized", "sd_x_within",
                         "ecom_pct_change_per_within_sd", "ecom_percent_change",
                         "interpretation_unit")], digits = 4, row.names = FALSE)
}
## 
## ================ BẢNG 9: HỆ SỐ CHUẨN HOÁ & Ý NGHĨA KINH TẾ (MÔ HÌNH CRE CHÍNH) ================
##                      term   estimate beta_standardized sd_x_within ecom_pct_change_per_within_sd ecom_percent_change
##                    iq_avg  0.0306525          0.010392     0.08340                         0.256              3.1127
##                       pdi -0.0035597         -0.038807          NA                            NA             -3.4971
##                       idv -0.0118636         -0.139254          NA                            NA            -11.1869
##                       mas  0.0023906          0.026719          NA                            NA              2.4194
##                       uai  0.0035679          0.043977          NA                            NA              3.6323
##                       lto  0.0006345          0.006961          NA                            NA              0.6365
##                       ivr -0.0102893         -0.102649          NA                            NA             -9.7776
##                  ln_gdppc  1.1366774          0.468370     0.08909                        10.658            211.6397
##             ln_population  0.4699575          0.394800     0.03363                         1.593             59.9926
##        internet_users_pct  0.0122864          0.087872     8.72162                        11.311              1.2362
##    private_credit_pct_gdp -0.0022078         -0.049253    11.40214                        -2.486             -0.2205
##        trade_open_pct_gdp  0.0016669          0.071003    11.27172                         1.897              0.1668
##  secondary_enrollment_pct  0.0048980          0.040400     5.18632                         2.573              0.4910
##                    interpretation_unit
##                          +1 đơn vị WGI
##                      +10 điểm Hofstede
##                      +10 điểm Hofstede
##                      +10 điểm Hofstede
##                      +10 điểm Hofstede
##                      +10 điểm Hofstede
##                      +10 điểm Hofstede
##  +1 đơn vị log (Độ co giãn = estimate)
##  +1 đơn vị log (Độ co giãn = estimate)
##                  +1 điểm phần trăm (%)
##                  +1 điểm phần trăm (%)
##                  +1 điểm phần trăm (%)
##                  +1 điểm phần trăm (%)
# ==============================================================================
# BƯỚC 10: KIỂM ĐỊNH ĐỘ BỀN (ROBUSTNESS CHECKS - 13 ĐẶC TẢ) [FIX 2, 6, 8] ====
# -> Chạy 13 đặc tả độ bền (bỏ biến giáo dục, chỉ giữ quan sát gốc, mẫu thận trọng,
#    bỏ năm COVID 2020-2021, bỏ 3 nền kinh tế lớn USA-CHN-JPN, TMĐT bình quân đầu
#    người, trễ 1 năm của thể chế, giai đoạn 2016-2024, loại ô nội suy/bước nhảy...).
# -> Cách chạy: Bôi đen toàn bộ Bước 10 và nhấn Ctrl + Enter (mất khoảng 10-20 giây).
# ==============================================================================

df_percap <- df |>
  dplyr::mutate(ecom_pc_usd = 1e6 * ecom_musd / population_total,
                ln_ecom_pc = log(ecom_pc_usd))

df_lag <- df |>
  dplyr::group_by(iso3) |>
  dplyr::arrange(year, .by_group = TRUE) |>
  dplyr::mutate(
    iq_avg_l1 = dplyr::if_else(
      year - dplyr::lag(year) == 1L, dplyr::lag(iq_avg), NA_real_
    )
  ) |>
  dplyr::ungroup() |>
  dplyr::filter(!is.na(iq_avg_l1)) |>
  as.data.frame()

robust_specifications <- list(
  Baseline_full = list(data = df, institution = "iq_avg", controls = controls_full, outcome = "ln_ecom"),
  Without_education = list(data = df, institution = "iq_avg",
                           controls = setdiff(controls_full, "secondary_enrollment_pct"), outcome = "ln_ecom"),
  Observed_only = list(data = subset(df, observed_only_sample == 1),
                       institution = "iq_avg", controls = controls_full, outcome = "ln_ecom"),
  Conservative_sample = list(data = subset(df, conservative_sample == 1),
                             institution = "iq_avg", controls = controls_full, outcome = "ln_ecom"),
  No_high_risk = list(data = subset(df, high_risk_cell_count == 0),
                      institution = "iq_avg", controls = controls_full, outcome = "ln_ecom"),
  Without_COVID_2020_2021 = list(data = subset(df, !(year %in% c(2020, 2021))),
                                 institution = "iq_avg", controls = controls_full, outcome = "ln_ecom"),
  Without_USA_CHN_JPN = list(data = subset(df, !(iso3 %in% c("USA", "CHN", "JPN"))),
                             institution = "iq_avg", controls = controls_full, outcome = "ln_ecom"),
  Ecom_per_capita = list(data = df_percap, institution = "iq_avg",
                         controls = setdiff(controls_full, "ln_population"), outcome = "ln_ecom_pc"),
  Institution_lag_1y = list(data = df_lag, institution = "iq_avg_l1",
                            controls = controls_full, outcome = "ln_ecom"),
  Period_2016_2024 = list(data = subset(df, year >= 2016), institution = "iq_avg",
                          controls = controls_full, outcome = "ln_ecom")
)

if ("ecom_imputed" %in% names(df)) {
  robust_specifications[["Ecom_observed_only"]] <- list(
    data = subset(df, ecom_imputed == 0), institution = "iq_avg",
    controls = controls_full, outcome = "ln_ecom"
  )
}
if (all(c("ecom_imputed", "ecom_unverified") %in% names(df))) {
  robust_specifications[["Ecom_source_values_only"]] <- list(
    data = subset(df, ecom_imputed == 0 & ecom_unverified == 0),
    institution = "iq_avg", controls = controls_full, outcome = "ln_ecom"
  )
}
if ("ecom_jump_country" %in% names(df)) {
  robust_specifications[["Without_ecom_jump_countries"]] <- list(
    data = subset(df, ecom_jump_country == 0), institution = "iq_avg",
    controls = controls_full, outcome = "ln_ecom"
  )
}

robust_joint_models <- list()
robust_details <- list()
robust_samples <- list()

for (label in names(robust_specifications)) {
  sp <- robust_specifications[[label]]
  robust_samples[[label]] <- data.frame(
    specification    = label,
    sample_rows      = nrow(sp$data),
    sample_countries = dplyr::n_distinct(sp$data$iso3),
    sample_years     = dplyr::n_distinct(sp$data$year)
  )
  joint <- safe_call(fit_cre(sp$data, institution = sp$institution,
                             culture = culture_vars, controls = sp$controls,
                             y = sp$outcome), paste0(label, " [joint 6 culture]"))
  robust_joint_models[[label]] <- joint
  for (inf in c("cluster", "cr2")) {
    robust_details[[paste(label, "joint", inf, sep = "_")]] <- collect_coefs(
      joint, paste0(label, "_joint"), inf, keep = c(sp$institution, culture_vars)
    )
  }
  # Đối chiếu hệ số thể chế với FE trên cùng mẫu con
  fe_same <- safe_call({
    need <- c("iso3", "year", sp$outcome, sp$institution, sp$controls)
    dd <- sp$data[stats::complete.cases(sp$data[need]), , drop = FALSE]
    plm::plm(make_formula(sp$outcome, sp$institution, character(), sp$controls),
             data = plm::pdata.frame(dd, index = c("iso3", "year"), drop.index = FALSE),
             model = "within", effect = "individual")
  }, paste0(label, " [FE check]"))
  for (inf in c("cluster", "cr2")) {
    robust_details[[paste(label, "FE", inf, sep = "_")]] <- collect_coefs(
      fe_same, paste0(label, "_FE_check"), inf, keep = sp$institution
    )
  }
}
##   [Lưu ý FIX 2] Swamy-Arora không khả dụng trên mẫu không cân bằng; tự động chuyển sang Wallace-Hussain.
##   [Lưu ý FIX 2] Swamy-Arora không khả dụng trên mẫu không cân bằng; tự động chuyển sang Wallace-Hussain.
##   [Lưu ý FIX 2] Swamy-Arora không khả dụng trên mẫu không cân bằng; tự động chuyển sang Wallace-Hussain.
##   [Lưu ý FIX 2] Swamy-Arora không khả dụng trên mẫu không cân bằng; tự động chuyển sang Wallace-Hussain.
##   [Lưu ý FIX 2] Swamy-Arora không khả dụng trên mẫu không cân bằng; tự động chuyển sang Wallace-Hussain.
robust_samples_df <- do.call(rbind, robust_samples)
cat("\n================ BẢNG 10A: CỠ MẪU CỦA CÁC ĐẶC TẢ KIỂM ĐỊNH ĐỘ BỀN ================\n")
## 
## ================ BẢNG 10A: CỠ MẪU CỦA CÁC ĐẶC TẢ KIỂM ĐỊNH ĐỘ BỀN ================
print(robust_samples_df, row.names = FALSE)
##                specification sample_rows sample_countries sample_years
##                Baseline_full         481               37           13
##            Without_education         481               37           13
##                Observed_only         420               36           13
##          Conservative_sample         449               36           13
##                 No_high_risk         449               36           13
##      Without_COVID_2020_2021         407               37           11
##          Without_USA_CHN_JPN         442               34           13
##              Ecom_per_capita         481               37           13
##           Institution_lag_1y         444               37           12
##             Period_2016_2024         333               37            9
##           Ecom_observed_only         444               37           13
##      Ecom_source_values_only         374               36           13
##  Without_ecom_jump_countries         338               26           13
# Hiển thị bảng kết quả các mô hình độ bền trên Console
print_model_table(
  robust_joint_models,
  heading = "BẢNG 10B: KẾT QUẢ KIỂM ĐỊNH ĐỘ BỀN (MÔ HÌNH ĐẦY ĐỦ 6 CHIỀU VĂN HOÁ - HC1)",
  keep = c("iq_avg", "iq_avg_l1", culture_vars)
)
## 
## ==============================================================================
## BẢNG 10B: KẾT QUẢ KIỂM ĐỊNH ĐỘ BỀN (MÔ HÌNH ĐẦY ĐỦ 6 CHIỀU VĂN HOÁ - HC1) 
## Ghi chú: Hệ số ước lượng kèm sai số chuẩn (CLUSTER) trong ngoặc đơn.
## Mức ý nghĩa: * p < 0.10; ** p < 0.05; *** p < 0.01. Đã kiểm soát hiệu ứng năm.
## ==============================================================================
##  Variable         Baseline_full      Without_education  Observed_only      Conservative_sample No_high_risk     
##  iq_avg           0.0307 (0.2801)    0.0060 (0.2805)    0.0195 (0.2787)    -0.0645 (0.2778)    -0.0645 (0.2778) 
##  iq_avg_l1                                                                                                      
##  pdi              -0.0036 (0.0061)   -0.0028 (0.0056)   -0.0030 (0.0068)   -0.0027 (0.0065)    -0.0027 (0.0065) 
##  idv              -0.0119** (0.0052) -0.0094** (0.0043) -0.0099** (0.0048) -0.0101* (0.0052)   -0.0101* (0.0052)
##  mas              0.0024 (0.0032)    0.0011 (0.0031)    0.0018 (0.0033)    0.0021 (0.0032)     0.0021 (0.0032)  
##  uai              0.0036 (0.0036)    0.0049 (0.0039)    0.0024 (0.0038)    0.0012 (0.0037)     0.0012 (0.0037)  
##  lto              0.0006 (0.0045)    0.0010 (0.0044)    0.0046 (0.0051)    0.0043 (0.0049)     0.0043 (0.0049)  
##  ivr              -0.0103* (0.0055)  -0.0091* (0.0048)  -0.0080 (0.0057)   -0.0090 (0.0058)    -0.0090 (0.0058) 
##  Observations (N) 481                481                420                449                 449              
##  Countries        37                 37                 36                 36                  36               
##  Without_COVID_2020_2021 Without_USA_CHN_JPN Ecom_per_capita   Institution_lag_1y Period_2016_2024  
##  0.0318 (0.2891)         -0.0945 (0.2842)    0.0656 (0.2591)                      -0.1278 (0.2426)  
##                                                                0.0023 (0.2729)                      
##  -0.0035 (0.0065)        -0.0030 (0.0064)    -0.0009 (0.0063)  -0.0034 (0.0061)   -0.0024 (0.0053)  
##  -0.0118** (0.0054)      -0.0120** (0.0054)  -0.0094* (0.0049) -0.0115** (0.0050) -0.0109** (0.0050)
##  0.0026 (0.0033)         0.0022 (0.0040)     0.0054* (0.0030)  0.0023 (0.0031)    0.0029 (0.0031)   
##  0.0035 (0.0037)         0.0056 (0.0044)     0.0000 (0.0040)   0.0029 (0.0037)    0.0025 (0.0036)   
##  -0.0002 (0.0047)        0.0005 (0.0051)     0.0045 (0.0044)   0.0010 (0.0045)    0.0043 (0.0044)   
##  -0.0104* (0.0059)       -0.0068 (0.0056)    -0.0087 (0.0057)  -0.0107** (0.0054) -0.0095** (0.0047)
##  407                     442                 481               444                333               
##  37                      34                  37                37                 37                
##  Ecom_observed_only  Ecom_source_values_only Without_ecom_jump_countries
##  0.1519 (0.2664)     0.2284 (0.2898)         0.0950 (0.2302)            
##                                                                         
##  -0.0052 (0.0061)    -0.0021 (0.0057)        0.0025 (0.0049)            
##  -0.0141*** (0.0053) -0.0094** (0.0043)      -0.0143* (0.0079)          
##  0.0030 (0.0032)     0.0018 (0.0032)         0.0040 (0.0040)            
##  0.0039 (0.0039)     0.0028 (0.0045)         0.0002 (0.0035)            
##  -0.0011 (0.0046)    0.0042 (0.0051)         -0.0015 (0.0043)           
##  -0.0085 (0.0052)    -0.0038 (0.0062)        -0.0086 (0.0070)           
##  444                 374                     338                        
##  37                  36                      26
# Tổng hợp riêng kết quả kiểm định độ bền theo CR2 để tra cứu nhanh
robust_results <- dplyr::bind_rows(robust_details)
robust_cr2_summary <- subset(robust_results, inference == "cr2" & grepl("_joint$|_FE_check$", model))
cat("\n================ BẢNG 10C: HỆ SỐ THỂ CHẾ & VĂN HOÁ QUA CÁC KIỂM ĐỊNH ĐỘ BỀN (CR2) ================\n")
## 
## ================ BẢNG 10C: HỆ SỐ THỂ CHẾ & VĂN HOÁ QUA CÁC KIỂM ĐỊNH ĐỘ BỀN (CR2) ================
print(robust_cr2_summary[, c("model", "N", "countries", "term", "estimate", "std_error", "df", "p_value")],
      digits = 4, row.names = FALSE)
##                                 model   N countries      term    estimate std_error     df p_value
##                   Baseline_full_joint 481        37    iq_avg  0.03065253  0.310009 16.427 0.92243
##                   Baseline_full_joint 481        37       pdi -0.00355973  0.008050  7.951 0.67013
##                   Baseline_full_joint 481        37       idv -0.01186360  0.006881  8.503 0.12075
##                   Baseline_full_joint 481        37       mas  0.00239060  0.004027  7.902 0.56939
##                   Baseline_full_joint 481        37       uai  0.00356793  0.004689 11.534 0.46199
##                   Baseline_full_joint 481        37       lto  0.00063453  0.005962 10.672 0.91721
##                   Baseline_full_joint 481        37       ivr -0.01028930  0.007376 10.445 0.19199
##                Baseline_full_FE_check 481        37    iq_avg  0.03065253  0.310009 16.427 0.92243
##               Without_education_joint 481        37    iq_avg  0.00602201  0.311282 16.403 0.98480
##               Without_education_joint 481        37       pdi -0.00279604  0.007189  8.208 0.70721
##               Without_education_joint 481        37       idv -0.00940816  0.005575 10.736 0.12027
##               Without_education_joint 481        37       mas  0.00109009  0.003770  7.496 0.78030
##               Without_education_joint 481        37       uai  0.00485541  0.005024 12.561 0.35203
##               Without_education_joint 481        37       lto  0.00098004  0.005689 10.731 0.86643
##               Without_education_joint 481        37       ivr -0.00908780  0.006203 10.057 0.17343
##            Without_education_FE_check 481        37    iq_avg  0.00602201  0.311282 16.403 0.98480
##                   Observed_only_joint 420        36    iq_avg  0.01949649  0.312028 15.218 0.95099
##                   Observed_only_joint 420        36       pdi -0.00304646  0.008721  8.171 0.73568
##                   Observed_only_joint 420        36       idv -0.00992635  0.006238  8.237 0.14910
##                   Observed_only_joint 420        36       mas  0.00184294  0.004203  8.000 0.67262
##                   Observed_only_joint 420        36       uai  0.00235143  0.005030 10.864 0.64937
##                   Observed_only_joint 420        36       lto  0.00463339  0.007281  9.601 0.53941
##                   Observed_only_joint 420        36       ivr -0.00802859  0.007547 10.012 0.31237
##                Observed_only_FE_check 420        36    iq_avg  0.02024706  0.311394 15.217 0.94900
##             Conservative_sample_joint 449        36    iq_avg -0.06453848  0.312056 15.848 0.83879
##             Conservative_sample_joint 449        36       pdi -0.00269848  0.008439  8.122 0.75721
##             Conservative_sample_joint 449        36       idv -0.01014042  0.006846  8.201 0.17594
##             Conservative_sample_joint 449        36       mas  0.00206432  0.004038  7.860 0.62324
##             Conservative_sample_joint 449        36       uai  0.00119604  0.004786 10.986 0.80726
##             Conservative_sample_joint 449        36       lto  0.00429181  0.006943  9.513 0.55100
##             Conservative_sample_joint 449        36       ivr -0.00897837  0.007807 10.014 0.27688
##          Conservative_sample_FE_check 449        36    iq_avg -0.06410890  0.311725 15.848 0.83968
##                    No_high_risk_joint 449        36    iq_avg -0.06453848  0.312056 15.848 0.83879
##                    No_high_risk_joint 449        36       pdi -0.00269848  0.008439  8.122 0.75721
##                    No_high_risk_joint 449        36       idv -0.01014042  0.006846  8.201 0.17594
##                    No_high_risk_joint 449        36       mas  0.00206432  0.004038  7.860 0.62324
##                    No_high_risk_joint 449        36       uai  0.00119604  0.004786 10.986 0.80726
##                    No_high_risk_joint 449        36       lto  0.00429181  0.006943  9.513 0.55100
##                    No_high_risk_joint 449        36       ivr -0.00897837  0.007807 10.014 0.27688
##                 No_high_risk_FE_check 449        36    iq_avg -0.06410890  0.311725 15.848 0.83968
##         Without_COVID_2020_2021_joint 407        37    iq_avg  0.03178328  0.317640 17.154 0.92146
##         Without_COVID_2020_2021_joint 407        37       pdi -0.00351390  0.008482  8.002 0.68956
##         Without_COVID_2020_2021_joint 407        37       idv -0.01182007  0.007044  8.649 0.12902
##         Without_COVID_2020_2021_joint 407        37       mas  0.00262953  0.004207  7.802 0.54982
##         Without_COVID_2020_2021_joint 407        37       uai  0.00350914  0.004826 11.693 0.48144
##         Without_COVID_2020_2021_joint 407        37       lto -0.00022171  0.006356 11.056 0.97279
##         Without_COVID_2020_2021_joint 407        37       ivr -0.01037652  0.007913 10.309 0.21819
##      Without_COVID_2020_2021_FE_check 407        37    iq_avg  0.03178328  0.317640 17.154 0.92146
##             Without_USA_CHN_JPN_joint 442        34    iq_avg -0.09448836  0.315163 14.948 0.76845
##             Without_USA_CHN_JPN_joint 442        34       pdi -0.00301010  0.008625  7.966 0.73613
##             Without_USA_CHN_JPN_joint 442        34       idv -0.01203595  0.007360  8.324 0.13916
##             Without_USA_CHN_JPN_joint 442        34       mas  0.00218291  0.005168  7.323 0.68486
##             Without_USA_CHN_JPN_joint 442        34       uai  0.00563633  0.006015  8.976 0.37327
##             Without_USA_CHN_JPN_joint 442        34       lto  0.00054095  0.006642  8.583 0.93696
##             Without_USA_CHN_JPN_joint 442        34       ivr -0.00675191  0.007577  8.051 0.39873
##          Without_USA_CHN_JPN_FE_check 442        34    iq_avg -0.09448836  0.315163 14.948 0.76845
##                 Ecom_per_capita_joint 481        37    iq_avg  0.06563699  0.284263 16.885 0.82017
##                 Ecom_per_capita_joint 481        37       pdi -0.00086644  0.008293  7.653 0.91948
##                 Ecom_per_capita_joint 481        37       idv -0.00944629  0.006489  9.106 0.17909
##                 Ecom_per_capita_joint 481        37       mas  0.00539844  0.003764 10.455 0.18069
##                 Ecom_per_capita_joint 481        37       uai  0.00000329  0.005044  8.251 0.99950
##                 Ecom_per_capita_joint 481        37       lto  0.00446703  0.005532 11.233 0.43617
##                 Ecom_per_capita_joint 481        37       ivr -0.00872354  0.007398 10.883 0.26345
##              Ecom_per_capita_FE_check 481        37    iq_avg  0.06563699  0.284263 16.885 0.82017
##              Institution_lag_1y_joint 444        37 iq_avg_l1  0.00232010  0.299788 14.980 0.99393
##              Institution_lag_1y_joint 444        37       pdi -0.00340672  0.007973  7.868 0.68064
##              Institution_lag_1y_joint 444        37       idv -0.01145468  0.006585  8.546 0.11775
##              Institution_lag_1y_joint 444        37       mas  0.00230501  0.003950  7.888 0.57586
##              Institution_lag_1y_joint 444        37       uai  0.00292602  0.004695 11.216 0.54560
##              Institution_lag_1y_joint 444        37       lto  0.00103084  0.005939 10.582 0.86547
##              Institution_lag_1y_joint 444        37       ivr -0.01074806  0.007165 10.495 0.16304
##           Institution_lag_1y_FE_check 444        37 iq_avg_l1  0.00232010  0.299788 14.980 0.99393
##                Period_2016_2024_joint 333        37    iq_avg -0.12782641  0.277302 14.146 0.65183
##                Period_2016_2024_joint 333        37       pdi -0.00235110  0.006942  7.346 0.74432
##                Period_2016_2024_joint 333        37       idv -0.01094492  0.006495  8.119 0.12991
##                Period_2016_2024_joint 333        37       mas  0.00286322  0.003879  8.118 0.48122
##                Period_2016_2024_joint 333        37       uai  0.00248421  0.004595 10.531 0.60001
##                Period_2016_2024_joint 333        37       lto  0.00425871  0.005688  9.833 0.47155
##                Period_2016_2024_joint 333        37       ivr -0.00949201  0.006047 10.925 0.14498
##             Period_2016_2024_FE_check 333        37    iq_avg -0.12782641  0.277302 14.146 0.65183
##              Ecom_observed_only_joint 444        37    iq_avg  0.15193771  0.288388 17.406 0.60495
##              Ecom_observed_only_joint 444        37       pdi -0.00522797  0.007949  7.994 0.52924
##              Ecom_observed_only_joint 444        37       idv -0.01406013  0.007028  8.782 0.07728
##              Ecom_observed_only_joint 444        37       mas  0.00304687  0.003991  7.889 0.46741
##              Ecom_observed_only_joint 444        37       uai  0.00392693  0.005031 11.809 0.45039
##              Ecom_observed_only_joint 444        37       lto -0.00111318  0.006172 10.333 0.86035
##              Ecom_observed_only_joint 444        37       ivr -0.00847149  0.006924 10.319 0.24835
##           Ecom_observed_only_FE_check 444        37    iq_avg  0.15116091  0.288558 17.406 0.60699
##         Ecom_source_values_only_joint 374        36    iq_avg  0.22835102  0.327851 14.447 0.49717
##         Ecom_source_values_only_joint 374        36       pdi -0.00212213  0.007542  7.318 0.78621
##         Ecom_source_values_only_joint 374        36       idv -0.00937591  0.005553  8.778 0.12645
##         Ecom_source_values_only_joint 374        36       mas  0.00179775  0.003965  7.520 0.66304
##         Ecom_source_values_only_joint 374        36       uai  0.00284782  0.005627 11.206 0.62259
##         Ecom_source_values_only_joint 374        36       lto  0.00416364  0.006593 11.031 0.54058
##         Ecom_source_values_only_joint 374        36       ivr -0.00383110  0.008102 10.826 0.64570
##      Ecom_source_values_only_FE_check 374        36    iq_avg  0.22926980  0.328030 14.447 0.49570
##     Without_ecom_jump_countries_joint 338        26    iq_avg  0.09500651  0.263265 11.555 0.72470
##     Without_ecom_jump_countries_joint 338        26       pdi  0.00246785  0.007012  4.503 0.74075
##     Without_ecom_jump_countries_joint 338        26       idv -0.01425277  0.009617  8.312 0.17520
##     Without_ecom_jump_countries_joint 338        26       mas  0.00401523  0.005640  5.451 0.50583
##     Without_ecom_jump_countries_joint 338        26       uai  0.00023326  0.004714  6.308 0.96207
##     Without_ecom_jump_countries_joint 338        26       lto -0.00148212  0.005493  7.671 0.79443
##     Without_ecom_jump_countries_joint 338        26       ivr -0.00862477  0.009777  6.326 0.40997
##  Without_ecom_jump_countries_FE_check 338        26    iq_avg  0.09500651  0.263265 11.555 0.72470
# ==============================================================================
# BƯỚC 11: PHÂN MẪU CÁC QUỐC GIA TƯƠNG ĐỒNG VỚI VIỆT NAM (TUỲ CHỌN) ====
# -> Việt Nam không nằm trong 37 nước của panel. Nếu bạn đã có điểm WGI trung bình
#    (iq_avg_m giai đoạn 2012-2024) và 6 điểm Hofstede của Việt Nam, hãy điền
#    vào dòng `vietnam_ref` bên dưới (thay các chữ NA_real_ bằng con số thực tế)
#    hoặc đặt file `vietnam_reference.csv` cùng thư mục rồi chạy Bước 11.
# -> Cách chạy: Bôi đen toàn bộ Bước 11 và nhấn Ctrl + Enter.
# ==============================================================================

# Bạn có thể điền trực tiếp 7 con số của Việt Nam vào đây (nếu không dùng file CSV):
vietnam_ref <- data.frame(
  iso3     = "VNM",
  iq_avg_m = NA_real_, # Điền trung bình WGI của Việt Nam (ví dụ: -0.42)
  pdi      = NA_real_, # Điền PDI của Việt Nam (ví dụ: 70)
  idv      = NA_real_, # Điền IDV của Việt Nam (ví dụ: 20)
  mas      = NA_real_, # Điền MAS của Việt Nam (ví dụ: 40)
  uai      = NA_real_, # Điền UAI của Việt Nam (ví dụ: 30)
  lto      = NA_real_, # Điền LTO của Việt Nam (ví dụ: 57)
  ivr      = NA_real_  # Điền IVR của Việt Nam (ví dụ: 35)
)

reference_path <- file.path(base_dir, "vietnam_reference.csv")
if (file.exists(reference_path)) {
  log_note("Đang đọc thông số tham chiếu Việt Nam từ file vietnam_reference.csv...")
  vietnam_ref <- safe_call(readr::read_csv(reference_path, show_col_types = FALSE),
                           "Vietnam reference CSV")
}

required_ref <- c("iq_avg_m", culture_vars)
valid_ref <- !is.null(vietnam_ref) && nrow(vietnam_ref) == 1L &&
  all(required_ref %in% names(vietnam_ref)) &&
  all(vapply(vietnam_ref[required_ref], function(z) is.numeric(z) &&
               length(z) == 1L && is.finite(z), logical(1)))

if (!valid_ref) {
  cat("\n[BƯỚC 11 - BỎ QUA]: Chưa có đủ 7 thông số tham chiếu của Việt Nam (iq_avg_m, pdi, idv, mas, uai, lto, ivr).\n")
  cat("-> Để chạy Bước 11, bạn chỉ cần thay các giá trị NA_real_ trong biến `vietnam_ref` ở đầu Bước 11\n")
  cat("   bằng số liệu WGI & Hofstede của Việt Nam rồi bôi đen Bước 11 nhấn Ctrl + Enter!\n")
} else {
  country_data <- df |>
    dplyr::group_by(iso3, country) |>
    dplyr::summarise(
      iq_avg_m = mean(iq_avg),
      dplyr::across(dplyr::all_of(culture_vars), dplyr::first),
      .groups = "drop"
    )
  country_data <- country_data[country_data$iso3 != "VNM", , drop = FALSE]
  attribute_matrix <- as.matrix(rbind(country_data[required_ref], vietnam_ref[required_ref]))
  storage.mode(attribute_matrix) <- "double"
  attr_mean <- colMeans(attribute_matrix)
  attr_sd <- apply(attribute_matrix, 2, sd)

  z <- scale(attribute_matrix, center = attr_mean, scale = attr_sd)
  ref_z <- z[nrow(z), , drop = FALSE]
  distance <- sqrt(rowSums((z[-nrow(z), , drop = FALSE] -
                              matrix(as.numeric(ref_z), nrow = nrow(z) - 1L,
                                     ncol = ncol(z), byrow = TRUE))^2))
  country_data$distance_to_VNM <- round(as.numeric(distance), 4)
  country_data <- country_data[order(country_data$distance_to_VNM, country_data$iso3), , drop = FALSE]
  country_data$similarity_rank <- seq_len(nrow(country_data))

  cat("\n================ BẢNG 11A: XẾP HẠNG MỨC ĐỘ TƯƠNG ĐỒNG VỚI VIỆT NAM ================\n")
  print(as.data.frame(country_data), digits = 4, row.names = FALSE)

  matched_results <- list()
  for (k in c(10L, 12L, 15L)) {
    eligible <- head(country_data$iso3, k)
    matched <- df[df$iso3 %in% eligible, , drop = FALSE]
    for (cv in culture_vars) {
      m <- safe_call(fit_cre(matched, culture = cv),
                     paste0("Vietnam match ", k, " countries / ", cv))
      for (inf in c("cluster", "cr2")) {
        matched_results[[paste(k, cv, inf, sep = "_")]] <- collect_coefs(
          m, paste0("VNM_nearest", k, "_", cv), inf, keep = c("iq_avg", cv)
        )
      }
    }
  }
  all_matched <- dplyr::bind_rows(matched_results)
  cat("\n================ BẢNG 11B: KẾT QUẢ CRE TRÊN PHÂN MẪU GẦN VIỆT NAM (10, 12, 15 NƯỚC) ================\n")
  print(subset(all_matched, inference == "cr2"), digits = 4, row.names = FALSE)
}
## 
## [BƯỚC 11 - BỎ QUA]: Chưa có đủ 7 thông số tham chiếu của Việt Nam (iq_avg_m, pdi, idv, mas, uai, lto, ivr).
## -> Để chạy Bước 11, bạn chỉ cần thay các giá trị NA_real_ trong biến `vietnam_ref` ở đầu Bước 11
##    bằng số liệu WGI & Hofstede của Việt Nam rồi bôi đen Bước 11 nhấn Ctrl + Enter!