///|
/// サブディレクトリの初期化機能
///
/// サブディレクトリを透過的な git 操作が可能な状態に初期化する。
/// - .git/subdir// に設定を作成
/// - サブディレクトリに .gitsubdir マーカーを作成
/// - オプションで git ラッパースクリプトを生成

///|
/// サブディレクトリを初期化
pub fn init_subdir(
  fs : &@bit.FileSystem,
  git_dir : String,
  repo_root : String,
  subdir_path : String,
  config : SubdirInitConfig,
) -> SubdirInfo raise SubdirError {
  let normalized_path = normalize_subdir_path(subdir_path)
  // サブディレクトリの絶対パス
  let subdir_abs = repo_root + "/" + normalized_path
  // .git/subdir// ディレクトリを作成
  let subdir_config_dir = git_dir +
    "/subdir/" +
    path_to_safe_name(normalized_path)
  fs.mkdir_p(subdir_config_dir) catch {
    _ => raise IoError("failed to create subdir config directory")
  }
  // 設定ファイルを作成
  let config_path = subdir_config_dir + "/config"
  let config_content = build_config_content(normalized_path, repo_root)
  fs.write_file(config_path, string_to_bytes_init(config_content)) catch {
    _ => raise IoError("failed to write config file")
  }
  // .gitsubdir マーカーファイルを作成
  let marker_path = subdir_abs + "/.gitsubdir"
  let marker_content = if config.verbose_marker {
    build_verbose_marker(normalized_path, git_dir)
  } else {
    "# This directory is managed as a git subdirectory\n"
  }
  fs.write_file(marker_path, string_to_bytes_init(marker_content)) catch {
    _ => raise IoError("failed to write marker file")
  }
  // git ラッパースクリプトを生成
  if config.create_wrapper {
    create_wrapper_script(fs, subdir_abs, normalized_path) catch {
      e => raise e
    }
  }
  { path: normalized_path, git_dir, config_path, initialized: true }
}

///|
/// サブディレクトリが初期化済みかチェック
pub fn is_subdir_initialized(
  rfs : &@bit.RepoFileSystem,
  git_dir : String,
  subdir_path : String,
) -> Bool {
  let normalized_path = normalize_subdir_path(subdir_path)
  let config_dir = git_dir + "/subdir/" + path_to_safe_name(normalized_path)
  let config_path = config_dir + "/config"
  rfs.is_file(config_path)
}

///|
/// 初期化済みサブディレクトリの情報を取得
pub fn get_subdir_info(
  rfs : &@bit.RepoFileSystem,
  git_dir : String,
  _repo_root : String,
  subdir_path : String,
) -> SubdirInfo? {
  let normalized_path = normalize_subdir_path(subdir_path)
  let config_dir = git_dir + "/subdir/" + path_to_safe_name(normalized_path)
  let config_path = config_dir + "/config"
  if rfs.is_file(config_path) {
    Some({ path: normalized_path, git_dir, config_path, initialized: true })
  } else {
    None
  }
}

///|
/// 初期化を解除
pub fn deinit_subdir(
  fs : &@bit.FileSystem,
  rfs : &@bit.RepoFileSystem,
  git_dir : String,
  repo_root : String,
  subdir_path : String,
) -> Unit {
  let normalized_path = normalize_subdir_path(subdir_path)
  let subdir_abs = repo_root + "/" + normalized_path
  // 設定ディレクトリを削除
  let config_dir = git_dir + "/subdir/" + path_to_safe_name(normalized_path)
  if rfs.is_dir(config_dir) {
    // config ファイルを削除
    fs.remove_file(config_dir + "/config") catch {
      _ => ()
    }
    fs.remove_dir(config_dir) catch {
      _ => ()
    }
  }
  // マーカーファイルを削除
  let marker_path = subdir_abs + "/.gitsubdir"
  fs.remove_file(marker_path) catch {
    _ => ()
  }
  // ラッパースクリプトを削除
  let wrapper_path = subdir_abs + "/git-subdir"
  fs.remove_file(wrapper_path) catch {
    _ => ()
  }
}

///|
/// シェル起動用の環境変数設定を生成
pub fn generate_shell_env(
  git_dir : String,
  repo_root : String,
  subdir_path : String,
) -> Array[(String, String)] {
  let normalized_path = normalize_subdir_path(subdir_path)
  [
    ("MOONGIT_SUBDIR", normalized_path),
    ("MOONGIT_GIT_DIR", git_dir),
    ("MOONGIT_REPO_ROOT", repo_root),
    ("GIT_PREFIX", normalized_path + "/"),
  ]
}

///|
/// シェル起動用の RC スクリプトを生成
pub fn generate_shell_rc(subdir_path : String) -> String {
  let normalized_path = normalize_subdir_path(subdir_path)
  let script = StringBuilder::new()
  // ヘッダー
  script.write_string("# Moongit subdir shell for: ")
  script.write_string(normalized_path)
  script.write_string("\n\n")
  // git ラッパー関数
  script.write_string("git() {\n")
  script.write_string("  local cmd=\"$1\"\n")
  script.write_string("  shift\n")
  script.write_string("  case \"$cmd\" in\n")
  // log コマンド
  script.write_string("    log)\n")
  script.write_string("      command git log \"$@\" -- .\n")
  script.write_string("      ;;\n")
  // status コマンド
  script.write_string("    status)\n")
  script.write_string("      command git status \"$@\" -- .\n")
  script.write_string("      ;;\n")
  // diff コマンド
  script.write_string("    diff)\n")
  script.write_string("      command git diff \"$@\" -- .\n")
  script.write_string("      ;;\n")
  // add コマンド
  script.write_string("    add)\n")
  script.write_string("      if [ $# -eq 0 ] || [ \"$1\" = \".\" ]; then\n")
  script.write_string("        command git add .\n")
  script.write_string("      else\n")
  script.write_string("        command git add \"$@\"\n")
  script.write_string("      fi\n")
  script.write_string("      ;;\n")
  // その他のコマンド
  script.write_string("    *)\n")
  script.write_string("      command git \"$cmd\" \"$@\"\n")
  script.write_string("      ;;\n")
  script.write_string("  esac\n")
  script.write_string("}\n\n")
  // プロンプト変更
  script.write_string("export PS1=\"[subdir:")
  script.write_string(normalized_path)
  script.write_string("] $PS1\"\n\n")
  // 終了時メッセージ
  script.write_string("echo \"Entered subdir shell for: ")
  script.write_string(normalized_path)
  script.write_string("\"\n")
  script.write_string("echo \"git commands are scoped to this directory.\"\n")
  script.write_string("echo \"Type 'exit' to return.\"\n")
  script.to_string()
}

///|
/// パスをファイル名安全な形式に変換(/ を _ に)
fn path_to_safe_name(path : String) -> String {
  let result = StringBuilder::new()
  for c in path {
    if c == '/' {
      result.write_char('_')
    } else {
      result.write_char(c)
    }
  }
  result.to_string()
}

///|
/// 設定ファイルの内容を生成
fn build_config_content(subdir_path : String, repo_root : String) -> String {
  let content = StringBuilder::new()
  content.write_string("[subdir]\n")
  content.write_string("\tpath = ")
  content.write_string(subdir_path)
  content.write_string("\n")
  content.write_string("\trepoRoot = ")
  content.write_string(repo_root)
  content.write_string("\n")
  content.write_string("\tinitialized = true\n")
  content.to_string()
}

///|
/// 詳細なマーカーファイルの内容を生成
fn build_verbose_marker(subdir_path : String, git_dir : String) -> String {
  let content = StringBuilder::new()
  content.write_string("# This directory is managed as a git subdirectory\n")
  content.write_string("# Do not edit this file manually\n")
  content.write_string("\n")
  content.write_string("path = ")
  content.write_string(subdir_path)
  content.write_string("\n")
  content.write_string("gitdir = ")
  content.write_string(git_dir)
  content.write_string("\n")
  content.to_string()
}

///|
/// git ラッパースクリプトを作成
fn create_wrapper_script(
  fs : &@bit.FileSystem,
  subdir_abs : String,
  subdir_path : String,
) -> Unit raise SubdirError {
  let script_path = subdir_abs + "/git-subdir"
  let script = StringBuilder::new()
  script.write_string("#!/bin/sh\n")
  script.write_string("# Git wrapper for subdirectory: ")
  script.write_string(subdir_path)
  script.write_string("\n\n")
  script.write_string("cmd=\"$1\"\n")
  script.write_string("shift\n\n")
  script.write_string("case \"$cmd\" in\n")
  script.write_string("  log|status|diff)\n")
  script.write_string("    git \"$cmd\" \"$@\" -- .\n")
  script.write_string("    ;;\n")
  script.write_string("  *)\n")
  script.write_string("    git \"$cmd\" \"$@\"\n")
  script.write_string("    ;;\n")
  script.write_string("esac\n")
  fs.write_file(script_path, string_to_bytes_init(script.to_string())) catch {
    _ => raise IoError("failed to write wrapper script")
  }
}

///|
/// String を Bytes に変換
fn string_to_bytes_init(s : String) -> Bytes {
  let bytes : Array[Byte] = []
  for c in s {
    bytes.push(c.to_int().to_byte())
  }
  Bytes::from_array(bytes)
}