#!/usr/bin/env bash
# Ikelabo Skills 自動インストーラー（macOS / Linux / WSL 用）
#
# 使い方（どちらでも同じ）:
#   curl -fsSL https://ikedalabo.com/wp-content/themes/ikelabo-renewal/assets/ikelabo-skills/install.sh | bash
#   bash install.sh [--dest DIR] [--dry-run]
#
# やること:
#   1. 公式 manifest.json から最新版のZIP URL・SHA-256・サイズを取得
#   2. ZIPをダウンロードし、SHA-256 とサイズを照合（改ざん・破損なら中止）
#   3. 一時フォルダへ展開し、ikelabo-skills/SKILL.md と VERSION を検証
#   4. 既存の ikelabo-skills があればバックアップへ退避してから差し替え
#   5. 配置先（既定: ~/.codex/skills/ikelabo-skills）と版を表示
#
# Python は使いません（初期状態のMacで python3 を呼ぶと開発者ツールの導入ダイアログが出るため）。
# 秘密情報は一切扱いません。ネットワーク先は ikedalabo.com のみです。

set -euo pipefail

BASE_URL="https://ikedalabo.com/wp-content/themes/ikelabo-renewal/assets/ikelabo-skills"
MANIFEST_URL="${BASE_URL}/manifest.json"
BUNDLE_NAME="ikelabo-skills"
CODEX_HOME="${CODEX_HOME:-$HOME/.codex}"
DEST_ROOT="${IKELABO_SKILLS_DIR:-$CODEX_HOME/skills}"
DRY_RUN=0
MAX_ARCHIVE_BYTES=$((64 * 1024 * 1024))

while [ $# -gt 0 ]; do
  case "$1" in
    --dest) DEST_ROOT="$2"; shift 2 ;;
    --dry-run) DRY_RUN=1; shift ;;
    -h|--help)
      sed -n '2,20p' "$0" 2>/dev/null || true
      exit 0 ;;
    *) echo "不明なオプション: $1" >&2; exit 2 ;;
  esac
done

DEST="${DEST_ROOT}/${BUNDLE_NAME}"

log()  { printf '%s\n' "$*"; }
fail() { printf 'IKELABO_INSTALL_FAILED: %s\n' "$*" >&2; exit 1; }

need() { command -v "$1" >/dev/null 2>&1 || fail "必要なコマンドがありません: $1"; }
need curl
need unzip

if command -v shasum >/dev/null 2>&1; then
  sha256() { shasum -a 256 "$1" | awk '{print $1}'; }
elif command -v sha256sum >/dev/null 2>&1; then
  sha256() { sha256sum "$1" | awk '{print $1}'; }
else
  fail "SHA-256 を計算するコマンド（shasum / sha256sum）がありません"
fi

TMP="$(mktemp -d "${TMPDIR:-/tmp}/ikelabo-skills-install.XXXXXX")"
cleanup() { rm -rf "$TMP"; }
trap cleanup EXIT

# 1. manifest 取得（JSON は1行1キーの整形済み。Pythonを使わず sed で読む）
log "最新版情報を取得しています..."
curl -fsSL --retry 3 --max-time 30 -o "$TMP/manifest.json" "$MANIFEST_URL" \
  || fail "manifest.json を取得できませんでした（ネットワークを確認してください）"
json_str() { sed -n "s/.*\"$1\"[[:space:]]*:[[:space:]]*\"\([^\"]*\)\".*/\1/p" "$TMP/manifest.json" | head -n1; }
json_num() { sed -n "s/.*\"$1\"[[:space:]]*:[[:space:]]*\([0-9][0-9]*\).*/\1/p" "$TMP/manifest.json" | head -n1; }
VERSION="$(json_str version)"
ZIP_URL="$(json_str zip_url)"
SHA="$(json_str sha256)"
SIZE="$(json_num size)"
BUNDLE_ROOT="$(json_str bundle_root)"
[ -n "$VERSION" ] && [ -n "$ZIP_URL" ] && [ -n "$SHA" ] && [ -n "$SIZE" ] || fail "manifest.json の内容が不正です"
[ "${BUNDLE_ROOT:-$BUNDLE_NAME}" = "$BUNDLE_NAME" ] || fail "bundle_root が想定と違います: $BUNDLE_ROOT"
case "$ZIP_URL" in
  "${BASE_URL}"/*.zip) ;;
  *) fail "配布URLが公式の場所ではありません: $ZIP_URL" ;;
esac
[ "$SIZE" -le "$MAX_ARCHIVE_BYTES" ] || fail "配布ZIPのサイズが大きすぎます: $SIZE"

# 既にその版が入っているか
if [ -f "$DEST/VERSION" ]; then
  LOCAL_VERSION="$(tr -d '[:space:]' < "$DEST/VERSION")"
else
  LOCAL_VERSION=""
fi
log "最新版: $VERSION  / 現在: ${LOCAL_VERSION:-未インストール}  / 配置先: $DEST"

# 2. ZIP 取得と照合
log "ZIP をダウンロードしています..."
curl -fsSL --retry 3 --max-time 180 -o "$TMP/bundle.zip" "$ZIP_URL" || fail "ZIP をダウンロードできませんでした"
ACTUAL_SIZE="$(wc -c < "$TMP/bundle.zip" | tr -d '[:space:]')"
[ "$ACTUAL_SIZE" = "$SIZE" ] || fail "ZIP サイズが一致しません（期待 $SIZE / 実際 $ACTUAL_SIZE）"
ACTUAL_SHA="$(sha256 "$TMP/bundle.zip")"
[ "$ACTUAL_SHA" = "$SHA" ] || fail "ZIP の SHA-256 が一致しません。ダウンロードをやり直してください"

# 3. 展開と検証（危険なパスを含む ZIP は中止）
if unzip -Z1 "$TMP/bundle.zip" | grep -Eq '(^/|(^|/)\.\.(/|$)|^[A-Za-z]:)'; then
  fail "ZIP に不正なパスが含まれています"
fi
if unzip -Z1 "$TMP/bundle.zip" | grep -Evq "^${BUNDLE_NAME}/"; then
  fail "ZIP の直下が ${BUNDLE_NAME}/ ではありません"
fi
mkdir -p "$TMP/extract"
unzip -q "$TMP/bundle.zip" -d "$TMP/extract" || fail "ZIP を展開できませんでした"
STAGED="$TMP/extract/$BUNDLE_NAME"
[ -f "$STAGED/SKILL.md" ] || fail "展開結果に SKILL.md がありません"
STAGED_VERSION="$(tr -d '[:space:]' < "$STAGED/VERSION" 2>/dev/null || true)"
[ "$STAGED_VERSION" = "$VERSION" ] || fail "VERSION が manifest と一致しません（$STAGED_VERSION / $VERSION）"
# 展開物から不要ファイルを除去
find "$STAGED" \( -name '.DS_Store' -o -name '__MACOSX' \) -prune -exec rm -rf {} + 2>/dev/null || true

if [ "$DRY_RUN" = "1" ]; then
  log "IKELABO_INSTALL_DRY_RUN version=$VERSION path=$DEST"
  exit 0
fi

# 4. 差し替え（既存はバックアップへ）
mkdir -p "$DEST_ROOT"
if [ -e "$DEST" ]; then
  BACKUP_ROOT="$CODEX_HOME/skill-backups/ikelabo-skills-installer"
  mkdir -p "$BACKUP_ROOT"
  BACKUP="$BACKUP_ROOT/${BUNDLE_NAME}-${LOCAL_VERSION:-unknown}-$(date +%Y%m%d-%H%M%S)"
  mv "$DEST" "$BACKUP" || fail "既存フォルダを退避できませんでした: $DEST"
  log "既存の ${BUNDLE_NAME} を退避しました: $BACKUP"
fi
mv "$STAGED" "$DEST" || fail "配置に失敗しました: $DEST"

# 5. 旧方式（プロジェクト内 .agents/skills/ikelabo-skills）が残っていれば知らせる
#    旧フォルダの中に本人の成果物が入っている場合があるため、自動では動かさない・消さない。
#    （Ikelabo作業フォルダの AGENTS.md で、共通の ~/.codex/skills 側を優先するよう指示している）
PROJECT_DIR="${IKELABO_PROJECT_DIR:-$HOME/Documents/Codex/Ikelabo}"
LEGACY_DEFAULT="$PROJECT_DIR/.agents/skills/$BUNDLE_NAME"
if [ -n "$PROJECT_DIR" ] && [ "$PROJECT_DIR" != "-" ] && [ -d "$LEGACY_DEFAULT" ]; then
  log "IKELABO_LEGACY_FOUND=$LEGACY_DEFAULT"
  log "お知らせ: 以前の方式で入れたスキル本体が残っています。今後は新しい『Ikelabo』プロジェクト（$PROJECT_DIR）を開いて使ってください。旧フォルダは消さなくて大丈夫です。"
fi

# 6. Ikelabo専用プロジェクトフォルダ（Codexの「プロジェクトを作成」でソースフォルダーに指定する場所）を用意する
if [ -n "$PROJECT_DIR" ] && [ "$PROJECT_DIR" != "-" ]; then
  mkdir -p "$PROJECT_DIR/output" 2>/dev/null || true
  if [ -d "$PROJECT_DIR" ] && [ ! -f "$PROJECT_DIR/AGENTS.md" ]; then
    cat > "$PROJECT_DIR/AGENTS.md" <<'AGENTS_EOF'
# Ikelabo 作業フォルダ

このフォルダは、Ikelaboスキル（自己紹介ページ・ブログ・体験レポート・図解・漫画・チラシ・LP・セミナー資料・SNS展開・MEO・仕組み化など）専用の作業場所です。

- ここでの依頼は、まず `$ikelabo-skills`（ユーザー共通の `~/.codex/skills/ikelabo-skills`）を使うことを前提に判断する。「Ikelaboで」と付いていなくても、制作・発信・集客の依頼はIkelaboスキルで受ける。
- このフォルダの中に旧方式の `.agents/skills/ikelabo-skills` が残っていても、ユーザー共通の `~/.codex/skills/ikelabo-skills` の方を使う（旧フォルダは消さない）。
- このフォルダに `00_UserProfile/` がまだ無いときは、最初の制作依頼の前に一度だけ「最初の10分で、あなたの価値観と文体を登録しませんか？『私の発信の初期セットアップをして』と言うだけで始まります」と案内する（断られたら押し付けない）。
- 作ったものは `output/日付_内容/` に保存し、完成したら保存場所を分かりやすく伝える。
- 依頼が短くても、足りない材料（写真・メモ・URL・目的・相手）は1問ずつ聞いて進める。専門用語で聞き返さない。
- WordPressなどの接続情報は `~/Documents/Codex/private-env/` の接続ファイルを使い、中身やパスワードはチャットに表示しない。
- 公開・投稿・送信は、本人の確認を取ってから行う。
AGENTS_EOF
  fi
  if [ -d "$PROJECT_DIR" ] && [ ! -f "$PROJECT_DIR/はじめに.txt" ]; then
    cat > "$PROJECT_DIR/はじめに.txt" <<'README_EOF'
このフォルダは、Ikelaboスキル専用のCodexプロジェクトです。

使い方:
1. ChatGPTデスクトップアプリ（Codex）で、左側「プロジェクト」の右の＋ → ローカル → 次へ → 名前に Ikelabo → 「フォルダーを追加」でこのフォルダ（書類/Codex/Ikelabo）を選ぶ → 「プロジェクトを作成」。
2. 左側の「プロジェクト」に Ikelabo が出たら、次回からはそれを押して話しかけるだけ。
3. 作ったものは output フォルダに入ります。

このフォルダの中の AGENTS.md は、Codexへの指示書です。消さないでください。
README_EOF
  fi
  [ -d "$PROJECT_DIR" ] && log "IKELABO_PROJECT_DIR=$PROJECT_DIR"
fi

log ""
log "IKELABO_INSTALL_OK version=$VERSION path=$DEST"
log "Codex では次のターンから \$ikelabo-skills が使えます。"
log "Ikelabo専用の作業フォルダ: ${PROJECT_DIR:-（作成しない設定）}（Codexの「プロジェクト」の＋ → ローカル → 次へ → 名前 Ikelabo → フォルダーを追加 でこのフォルダを選ぶと、左側の一覧に Ikelabo が出ます）"
