# ============================================================
# 07_niche_cellchat.R —— 生态位内细胞通讯分析（对应教程第 12 章）
# 用法：Rscript code/07_niche_cellchat.R（或 RStudio 逐段运行）
# 前置：已运行 05_spatial_domain.R，读取 data/processed/visium_niche.rds
#       且 obj$niche 已包含命名后的生态位标签
# 核心思想：按生态位拆开数据，每个生态位独立建 CellChat，
#           得到"生态位特异的通讯程序"——这是本课题的创新点操作化。
# ============================================================

library(Seurat)
library(CellChat)
library(purrr)

obj <- readRDS("data/processed/visium_niche.rds")
table(obj$niche)   # 查看各生态位 spot 数（太少说明该生态位不适合单独分析）

## 1. 封装"生态位 CellChat"函数
run_niche_cellchat <- function(sub_obj) {
  cc <- createCellChat(object = sub_obj, group.by = "celltype")
  cc@DB <- CellChatDB.human
  cc <- subsetData(cc)
  cc <- identifyOverExpressedGenes(cc)
  cc <- identifyOverExpressedInteractions(cc)
  cc <- computeCommunProb(cc, type = "triMean")
  cc <- filterCommunication(cc, min.cells = 5)   # 生态位内群体更小，阈值放低
  cc <- computeCommunProbPathway(cc)
  cc <- aggregateNet(cc)
  cc
}

## 2. 对每个生态位跑一遍
niches <- unique(obj$niche)
cellchat_list <- set_names(lapply(niches, function(ni) {
  cat("正在分析生态位：", ni, "\n")
  sub <- subset(obj, subset = niche == ni)
  run_niche_cellchat(sub)
}), niches)

## 3. 汇总比较：通讯数量与强度（对应 fig13）
interaction_count <- sapply(cellchat_list, function(cc) sum(cc@net$count > 0))
interaction_strength <- sapply(cellchat_list, function(cc) sum(cc@net$weight))
summary_df <- data.frame(
  生态位 = niches,
  通讯数量 = interaction_count,
  通讯强度 = round(interaction_strength, 3)
)
print(summary_df)
write.csv(summary_df, "results/niche_communication_summary.csv", row.names = FALSE)

## 4. 可视化：各生态位网络并列
pdf("results/niche_networks.pdf", width = 16, height = 6)
par(mfrow = c(1, length(niches)))
for (ni in niches) {
  netVisual_circle(cellchat_list[[ni]], weight.scale = TRUE, label.edge = FALSE,
                   title.name = ni)
}
dev.off()

## 5. 保存
saveRDS(cellchat_list, "data/processed/cellchat_by_niche.rds")
cat("生态位分区通讯分析完成！结果：\n"); print(summary_df)
cat("下一步：code/08_differential_comm.R 做生态位间差异（重编程）分析。\n")
