"""
按组挂载 Git 资源（只读） + 自动建用户加组
资源路径 /home/zhangyi/jupyter-collection
控制文件 /home/zhangyi/jupyter-collection/.hub/resource_map.ini
"""

import os, grp, pwd, shutil, subprocess, configparser
from pathlib import Path
from jupyterhub.spawner import Spawner

# ---------- 路径常量 ----------
SHARED_ROOT = Path("/home/zhangyi/jupyter-collection")          # Git 资源仓库
USER_HOME   = Path("/home/jupyter-{username}")    # 用户家目录模板
CTRL_FILE   = SHARED_ROOT / ".hub" / "resource_map.ini"  # 组-资源-用户映射

# ---------- 工具：读控制表 ----------
def load_ctrl():
    """返回 (组->资源, 组->用户) 两个 dict"""
    cfg = configparser.ConfigParser()
    cfg.read(CTRL_FILE)
    res_map = {g: [r.strip() for r in v.split(",")] for g, v in cfg.items("map")}
    usr_map = {g: [u.strip() for u in v.split(",")] for g, v in cfg.items("users")}
    return res_map, usr_map

# ========== 最早钩子：预创建家目录 ==========
def ensure_homedir(spawner):
    """systemd 启动前保证目录存在且属主正确"""
    username = spawner.user.name
    user_dir = Path(str(USER_HOME).format(username=username))
    if not user_dir.exists():
        user_dir.mkdir(mode=0o700, parents=True)
    shutil.chown(user_dir, user=username, group=username)

c.Spawner.pre_spawn_hook = ensure_homedir

# ========== 认证后钩子：自动建用户+加组 ==========
def ensure_user_and_groups(authenticator, handler, authentication):
    username = authentication['name']
    res_map, usr_map = load_ctrl()
    wanted_groups = [g for g, users in usr_map.items() if username in users]
    if not wanted_groups:
        return authentication

    for g in wanted_groups:                      # 确保组存在
        subprocess.run(["groupadd", "-f", g], check=False)

    if subprocess.run(["id", "-u", username], capture_output=True).returncode != 0:
        subprocess.run([
            "useradd", "-m", "-s", "/bin/bash",
            "-d", str(USER_HOME).format(username=username), username
        ], check=False)

    for g in wanted_groups:                      # 加组
        subprocess.run(["usermod", "-aG", g, username], check=False)

    return authentication

c.Authenticator.post_auth_hook = ensure_user_and_groups

# ========== spawn 钩子：清 shared + 只读挂载 ==========

def prepare_user(spawner):
    username = spawner.user.name
    user_dir = Path(str(USER_HOME).format(username=username))

    # ① 确保家目录 700 + 属主正确（首次/后续都适用）
    user_dir.mkdir(mode=0o700, parents=True, exist_ok=True)
    shutil.chown(user_dir, user=username, group=username)

    # ② 只清 shared，保留用户其它文件
    shared = user_dir / "shared"
    if shared.exists():
        shutil.rmtree(shared)
    shared.mkdir(parents=True, exist_ok=True)
    shutil.chown(shared, user=username, group=username)

    # 读取控制表
    res_map, _ = load_ctrl()

    # 获取用户系统组
    try:
        pwnam = pwd.getpwnam(username)
        gid_list = os.getgrouplist(username, pwnam.pw_gid)
    except (KeyError, OSError):
        return
    user_groups = {grp.getgrgid(g).gr_name for g in gid_list}

    # 组装 bind_mounts（SystemdSpawner 语法）
    bind_list = []
    for grp_name in user_groups:
        for res in res_map.get(grp_name, []):
            res_path = SHARED_ROOT / res
            if res_path.is_dir():
                bind_list.append({
                    'source': str(res_path),
                    'target': str(shared / res),
                    'read-only': True,
                })
    spawner.bind_mounts = bind_list

c.Spawner.pre_spawn_hook = prepare_user