#!/bin/bash
# mk-init.sh — Install my-agent-kit into a target project
#
# Reads canonical content from ./claude/ and installs into target/.claude/
#
# Usage:
#   ./mk-init.sh                     # Install into current directory
#   ./mk-init.sh /path/to/project    # Install into specified project
#   ./mk-init.sh --dry-run           # Show what would be copied
#   ./mk-init.sh --force             # Overwrite existing .claude/
#   ./mk-init.sh --upgrade           # Apply deletions from metadata.json (clean upgrade)
#   ./mk-init.sh --skills-install    # Also run skills dependency installer
#   ./mk-init.sh --copilot           # Also generate .github/copilot-instructions.md
#   ./mk-init.sh --codex             # Also generate .codex/ + .agents/skills/ for Codex CLI
#   ./mk-init.sh --all               # Enable all cross-tool configs

set -e

# --- Config ---
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
KIT_NAME="my-agent-kit"
KIT_SOURCE="$SCRIPT_DIR/claude"          # Canonical kit content (no leading dot)
TARGET_KIT_NAME=".claude"                 # Target install location (Claude Code convention)

# Read version from package.json (single source of truth)
if [[ -f "$SCRIPT_DIR/package.json" ]]; then
    VERSION=$(grep -E '"version"' "$SCRIPT_DIR/package.json" | head -1 | sed -E 's/.*"version"[[:space:]]*:[[:space:]]*"([^"]+)".*/\1/')
else
    VERSION="2.0.0"
fi

# --- Colors ---
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
BOLD='\033[1m'
NC='\033[0m'

# --- Parse args ---
TARGET_DIR=""
DRY_RUN=false
FORCE=false
UPGRADE=false
SKILLS_INSTALL=false
COPILOT=false
CODEX=false

while [[ "$#" -gt 0 ]]; do
    case $1 in
        --dry-run) DRY_RUN=true ;;
        --force) FORCE=true ;;
        --upgrade) UPGRADE=true ;;
        --skills-install) SKILLS_INSTALL=true ;;
        --copilot) COPILOT=true ;;
        --codex) CODEX=true ;;
        --all) COPILOT=true; CODEX=true ;;
        -h|--help)
            cat <<HELP
Usage: mk-init.sh [target-dir] [options]

Options:
  --dry-run          Show what would be copied without doing it
  --force            Overwrite existing .claude/ directory
  --upgrade          Apply deletions from metadata.json before copy (clean upgrade)
  --skills-install   Run skills dependency installer after copy
  --copilot          Generate .github/copilot-instructions.md (Copilot reads .claude/ natively)
  --codex            Generate .codex/ + .agents/skills/ for Codex CLI
  --all              Enable all cross-tool configs (--copilot + --codex)
  -h, --help         Show this help

Examples:
  ./mk-init.sh                          # Install into current directory
  ./mk-init.sh ~/projects/my-app        # Install into specific project
  ./mk-init.sh . --force                # Reinstall / overwrite
  ./mk-init.sh . --upgrade --force      # Upgrade existing install (drop deleted files first)
  ./mk-init.sh . --copilot --codex      # Install with cross-tool support
  ./mk-init.sh . --all                  # Install with all cross-tool configs

About:
  Kit source: ./claude/   (canonical, version controlled)
  Target:     .claude/    (Claude Code reads from here)

HELP
            exit 0
            ;;
        *)
            if [[ -z "$TARGET_DIR" ]]; then
                TARGET_DIR="$1"
            else
                echo -e "${RED}Error: Unknown argument: $1${NC}"
                exit 1
            fi
            ;;
    esac
    shift
done

# Default to current directory
TARGET_DIR="${TARGET_DIR:-.}"
TARGET_DIR="$(cd "$TARGET_DIR" 2>/dev/null && pwd)" || {
    echo -e "${RED}Error: Target directory does not exist: $TARGET_DIR${NC}"
    exit 1
}

# --- Banner ---
echo ""
echo -e "${BOLD}${BLUE}$KIT_NAME v$VERSION — Project Installer${NC}"
echo ""
echo -e "  Source:  ${SCRIPT_DIR}/claude/"
echo -e "  Target:  ${TARGET_DIR}/${TARGET_KIT_NAME}/"
echo ""

# --- Sanity checks ---

# Don't install into self
if [[ "$TARGET_DIR" == "$SCRIPT_DIR" ]]; then
    echo -e "${RED}Error: Cannot install kit into itself.${NC}"
    exit 1
fi

# Verify canonical source exists
if [[ ! -d "$KIT_SOURCE" ]]; then
    echo -e "${RED}Error: Kit source not found at $KIT_SOURCE${NC}"
    echo -e "  Expected canonical content at ${SCRIPT_DIR}/claude/"
    exit 1
fi

# Check for existing .claude/
if [[ -d "$TARGET_DIR/$TARGET_KIT_NAME" ]] && [[ "$FORCE" != true ]] && [[ "$UPGRADE" != true ]]; then
    echo -e "${YELLOW}Warning: $TARGET_DIR/$TARGET_KIT_NAME/ already exists.${NC}"
    echo -e "  Use ${BOLD}--force${NC} to overwrite, ${BOLD}--upgrade${NC} for clean upgrade, or remove it first."
    exit 1
fi

# --- Excluded patterns (won't be copied into target) ---
EXCLUDE_PATTERNS=(
    "skills/.venv"
    "skills/.install-state.json"
    ".env"
    ".env.local"
    "session-state"
)

# Template files copied to project root
TEMPLATE_FILES=(
    "templates/CLAUDE.md"
    "templates/AGENTS.md"
)

# Optional directories (created if missing, not overwritten)
OPTIONAL_DIRS=(
    "plans"
)

# --- Dry run ---
if [[ "$DRY_RUN" == true ]]; then
    echo -e "${BLUE}Dry run — would perform these actions:${NC}"
    echo ""

    if [[ "$UPGRADE" == true ]] && [[ -f "$KIT_SOURCE/metadata.json" ]]; then
        echo -e "  ${YELLOW}[upgrade]${NC} Read deletions from claude/metadata.json"
        deletion_count=$(grep -cE '^\s*"[^"]+",?\s*$' "$KIT_SOURCE/metadata.json" 2>/dev/null || echo 0)
        echo -e "             (~${deletion_count} paths to drop from target/.claude/)"
    fi

    echo -e "  ${GREEN}[copy]${NC}     claude/* → $TARGET_DIR/$TARGET_KIT_NAME/"
    file_count=$(find "$KIT_SOURCE" -type f | wc -l | tr -d ' ')
    echo -e "             (${file_count} files)"

    for dir in "${OPTIONAL_DIRS[@]}"; do
        if [[ -d "$SCRIPT_DIR/$dir" ]]; then
            echo -e "  ${GREEN}[copy]${NC}     $dir/ → $TARGET_DIR/$dir/ (optional, skip if exists)"
        fi
    done
    for tpl in "${TEMPLATE_FILES[@]}"; do
        if [[ -f "$SCRIPT_DIR/$tpl" ]]; then
            echo -e "  ${GREEN}[copy]${NC}     $(basename "$tpl") → $TARGET_DIR/$(basename "$tpl") (from templates/)"
        fi
    done
    if [[ "$COPILOT" == true ]]; then
        echo -e "  ${GREEN}[generate]${NC} .github/copilot-instructions.md"
    fi
    if [[ "$CODEX" == true ]]; then
        echo -e "  ${GREEN}[generate]${NC} .codex/config.toml"
        echo -e "  ${GREEN}[generate]${NC} .codex/hooks.json"
        echo -e "  ${GREEN}[symlink]${NC}  .agents/skills/ → $TARGET_KIT_NAME/skills/"
    fi
    echo ""
    echo -e "  ${YELLOW}Excluded from copy:${NC}"
    for pat in "${EXCLUDE_PATTERNS[@]}"; do
        echo -e "    $pat"
    done
    exit 0
fi

# --- Upgrade step: apply deletions from metadata.json ---
# Some files removed in newer versions linger in old installs. Drop them
# from target/.claude/ before copying fresh content.
if [[ "$UPGRADE" == true ]] && [[ -f "$KIT_SOURCE/metadata.json" ]] && [[ -d "$TARGET_DIR/$TARGET_KIT_NAME" ]]; then
    echo -e "${BLUE}Applying clean upgrade — dropping deleted paths from target...${NC}"
    # Extract deletion paths from metadata.json (simple JSON array of strings)
    python3 - "$KIT_SOURCE/metadata.json" "$TARGET_DIR/$TARGET_KIT_NAME" <<'PY'
import json
import os
import shutil
import sys
import fnmatch

meta_path, target_root = sys.argv[1], sys.argv[2]
try:
    with open(meta_path) as f:
        meta = json.load(f)
except Exception as e:
    print(f"  [warn] could not read metadata.json: {e}")
    sys.exit(0)

dropped = 0
for entry in meta.get("deletions", []):
    # Support glob patterns (e.g. ".opencode/**")
    if any(c in entry for c in "*?["):
        for root, dirs, files in os.walk(target_root):
            for name in files + dirs:
                rel = os.path.relpath(os.path.join(root, name), target_root)
                if fnmatch.fnmatch(rel, entry) or fnmatch.fnmatch(rel, entry.rstrip("/**")):
                    path = os.path.join(target_root, rel)
                    try:
                        if os.path.isdir(path) and not os.path.islink(path):
                            shutil.rmtree(path)
                        else:
                            os.remove(path)
                        dropped += 1
                    except FileNotFoundError:
                        pass
    else:
        path = os.path.join(target_root, entry)
        if os.path.exists(path) or os.path.islink(path):
            try:
                if os.path.isdir(path) and not os.path.islink(path):
                    shutil.rmtree(path)
                else:
                    os.remove(path)
                dropped += 1
            except Exception as e:
                print(f"  [warn] could not drop {entry}: {e}")

print(f"  Dropped {dropped} deleted paths")
PY
fi

# --- Copy core: claude/ → target/.claude/ ---
echo -e "${BLUE}Installing...${NC}"
echo -e "  Copying ${BOLD}claude/${NC} → ${BOLD}${TARGET_KIT_NAME}/${NC}..."

if [[ "$FORCE" == true ]] && [[ -d "$TARGET_DIR/$TARGET_KIT_NAME" ]] && [[ "$UPGRADE" != true ]]; then
    rm -rf "$TARGET_DIR/$TARGET_KIT_NAME"
fi

# Build rsync exclude args
EXCLUDE_ARGS=()
for pat in "${EXCLUDE_PATTERNS[@]}"; do
    EXCLUDE_ARGS+=("--exclude=$pat")
done

rsync -a "${EXCLUDE_ARGS[@]}" "$KIT_SOURCE/" "$TARGET_DIR/$TARGET_KIT_NAME/"

# --- Copy optional dirs (don't overwrite) ---
for dir in "${OPTIONAL_DIRS[@]}"; do
    if [[ -d "$SCRIPT_DIR/$dir" ]]; then
        if [[ -d "$TARGET_DIR/$dir" ]]; then
            echo -e "  ${YELLOW}Skipping${NC} $dir/ (already exists)"
        else
            echo -e "  Copying ${BOLD}$dir/${NC}..."
            rsync -a "$SCRIPT_DIR/$dir/" "$TARGET_DIR/$dir/"
        fi
    fi
done

# --- Copy template files → project root (CLAUDE.md, AGENTS.md) ---
for tpl in "${TEMPLATE_FILES[@]}"; do
    target_name="$(basename "$tpl")"
    if [[ -f "$SCRIPT_DIR/$tpl" ]]; then
        if [[ -f "$TARGET_DIR/$target_name" ]] && [[ "$FORCE" != true ]]; then
            echo -e "  ${YELLOW}Skipping${NC} $target_name (already exists)"
        else
            echo -e "  Copying ${BOLD}$target_name${NC} (from templates/)..."
            cp "$SCRIPT_DIR/$tpl" "$TARGET_DIR/$target_name"
        fi
    fi
done

# --- Generate Copilot config ---
if [[ "$COPILOT" == true ]]; then
    mkdir -p "$TARGET_DIR/.github"

    if [[ -f "$TARGET_DIR/.github/copilot-instructions.md" ]] && [[ "$FORCE" != true ]]; then
        echo -e "  ${YELLOW}Skipping${NC} .github/copilot-instructions.md (already exists)"
    else
        echo -e "  Generating ${BOLD}.github/copilot-instructions.md${NC}..."
        cat > "$TARGET_DIR/.github/copilot-instructions.md" << 'COPILOT_EOF'
# Copilot Instructions

This project uses my-agent-kit. Copilot automatically reads:
- `CLAUDE.md` — project instructions (via `chat.useClaudeMdFile`)
- `.claude/rules/` — workflow and development rules
- `.claude/skills/` — domain knowledge packs (SKILL.md format)

No need to duplicate those here. This file is for Copilot-specific additions only.

## Copilot-Specific Notes

- Use conventional commits: `feat:`, `fix:`, `refactor:`, `test:`
- Plans go in `./plans/` with timestamp naming
- Read `./README.md` first for project context
- Read `./docs/code-standards.md` for code standards
COPILOT_EOF
    fi
fi

# --- Generate Codex config ---
if [[ "$CODEX" == true ]]; then
    mkdir -p "$TARGET_DIR/.codex"

    # config.toml
    if [[ -f "$TARGET_DIR/.codex/config.toml" ]] && [[ "$FORCE" != true ]]; then
        echo -e "  ${YELLOW}Skipping${NC} .codex/config.toml (already exists)"
    else
        echo -e "  Generating ${BOLD}.codex/config.toml${NC}..."
        cat > "$TARGET_DIR/.codex/config.toml" << 'CODEX_EOF'
# Codex CLI configuration for my-agent-kit
# Docs: https://github.com/openai/codex

# Codex reads AGENTS.md by default. Also read CLAUDE.md for richer context.
project_doc_fallback_filenames = ["CLAUDE.md"]

# model = "o4-mini"
# model_reasoning_effort = "medium"

[features]
codex_hooks = true
# multi_agent = true
CODEX_EOF
    fi

    # hooks.json
    if [[ -f "$TARGET_DIR/.codex/hooks.json" ]] && [[ "$FORCE" != true ]]; then
        echo -e "  ${YELLOW}Skipping${NC} .codex/hooks.json (already exists)"
    else
        echo -e "  Generating ${BOLD}.codex/hooks.json${NC}..."
        cat > "$TARGET_DIR/.codex/hooks.json" << 'HOOKS_EOF'
{
  "hooks": {
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "echo \"[my-agent-kit] Session started at $(date '+%Y-%m-%d %H:%M'). Read AGENTS.md for project instructions.\"",
            "timeoutSec": 5
          }
        ]
      }
    ],
    "PreToolUse": [
      {
        "matcher": "Bash|shell",
        "hooks": [
          {
            "type": "command",
            "command": "echo \"[reminder] Follow development rules: YAGNI, KISS, DRY. Run tests before push.\"",
            "timeoutSec": 5
          }
        ]
      }
    ]
  }
}
HOOKS_EOF
    fi

    # Symlink .agents/skills/ → .claude/skills/
    mkdir -p "$TARGET_DIR/.agents"
    if [[ -L "$TARGET_DIR/.agents/skills" ]]; then
        if [[ "$FORCE" == true ]]; then
            rm "$TARGET_DIR/.agents/skills"
            ln -s "../$TARGET_KIT_NAME/skills" "$TARGET_DIR/.agents/skills"
            echo -e "  Linking ${BOLD}.agents/skills/${NC} → $TARGET_KIT_NAME/skills/"
        else
            echo -e "  ${YELLOW}Skipping${NC} .agents/skills symlink (already exists)"
        fi
    elif [[ -d "$TARGET_DIR/.agents/skills" ]]; then
        echo -e "  ${YELLOW}Skipping${NC} .agents/skills (directory exists, not overwriting)"
    else
        ln -s "../$TARGET_KIT_NAME/skills" "$TARGET_DIR/.agents/skills"
        echo -e "  Linking ${BOLD}.agents/skills/${NC} → $TARGET_KIT_NAME/skills/"
    fi
fi

# --- Post-install: skills dependencies ---
if [[ "$SKILLS_INSTALL" == true ]]; then
    INSTALL_SCRIPT="$TARGET_DIR/$TARGET_KIT_NAME/skills/install.sh"
    if [[ -f "$INSTALL_SCRIPT" ]]; then
        echo ""
        echo -e "${BLUE}Running skills dependency installer...${NC}"
        chmod +x "$INSTALL_SCRIPT"
        bash "$INSTALL_SCRIPT" -y
    else
        echo -e "${YELLOW}Warning: install.sh not found, skipping skills install.${NC}"
    fi
fi

# --- Summary ---
echo ""
echo -e "${GREEN}${BOLD}Done!${NC} Kit installed to: $TARGET_DIR"
echo ""
echo -e "  ${BOLD}Installed:${NC}"
echo -e "    $TARGET_KIT_NAME/         agents, rules, skills, hooks, scripts, statusline"
echo -e "    AGENTS.md         project instructions (Codex + other tools read this)"
if [[ "$COPILOT" == true ]]; then
echo -e "    .github/          copilot-instructions.md (extras only — Copilot reads $TARGET_KIT_NAME/ natively)"
fi
if [[ "$CODEX" == true ]]; then
echo -e "    .codex/           config.toml + hooks.json"
echo -e "    .agents/skills/   → $TARGET_KIT_NAME/skills/ (symlink for Codex skill discovery)"
fi
echo ""
echo -e "  ${BOLD}Next steps:${NC}"
echo -e "    cd $TARGET_DIR"
echo -e "    claude                              # Start Claude Code"
if [[ "$CODEX" == true ]]; then
echo -e "    codex                               # Start Codex CLI"
fi
if [[ "$COPILOT" == true ]]; then
echo -e ""
echo -e "  ${BOLD}Copilot setup:${NC}"
echo -e "    In VS Code settings.json, add:"
echo -e "    ${YELLOW}\"github.copilot.chat.codeGeneration.useInstructionFiles\": true${NC}"
fi
echo ""
echo -e "    $TARGET_KIT_NAME/skills/install.sh -y        # (optional) Install skill dependencies"
echo ""
