#!/bin/bash
#
# solomd - CLI for SoloMD Markdown Editor
# https://github.com/zhitongblog/solomd
#
# Usage:
#   solomd open <title|path>     Open a markdown file in SoloMD
#   solomd new <title> [text]    Create a new markdown file and open it
#   solomd list [folder]         List markdown files in a folder
#   solomd search <query>        Search markdown files in CWD for a query
#   solomd cat <title|path>      Print a markdown file's content
#   solomd help                  Show this help
#
# Notes:
#   - Default notes directory: $SOLOMD_NOTES (or ~/Documents/SoloMD if unset)
#   - "title" arguments resolve to <notes-dir>/<title>.md if no extension is
#     given. Pass an explicit path to bypass this.

set -e

# ---- Colors --------------------------------------------------------------
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[0;33m'
DIM='\033[2m'
NC='\033[0m'

# ---- Notes dir resolution ------------------------------------------------
NOTES_DIR="${SOLOMD_NOTES:-$HOME/Documents/SoloMD}"

ensure_notes_dir() {
    if [[ ! -d "$NOTES_DIR" ]]; then
        mkdir -p "$NOTES_DIR"
    fi
}

# ---- App binary detection ------------------------------------------------
detect_solomd_bin() {
    if [[ "$(uname)" == "Darwin" ]]; then
        local mac_paths=(
            "/Applications/SoloMD.app/Contents/MacOS/SoloMD"
            "$HOME/Applications/SoloMD.app/Contents/MacOS/SoloMD"
        )
        for p in "${mac_paths[@]}"; do
            [[ -x "$p" ]] && echo "$p" && return 0
        done
    elif [[ "$(uname)" == "Linux" ]]; then
        for cmd in solomd SoloMD; do
            if command -v "$cmd" >/dev/null 2>&1; then
                command -v "$cmd"
                return 0
            fi
        done
        local linux_paths=(
            "/usr/bin/solomd"
            "/usr/local/bin/solomd"
            "/opt/SoloMD/solomd"
        )
        for p in "${linux_paths[@]}"; do
            [[ -x "$p" ]] && echo "$p" && return 0
        done
    fi
    return 1
}

# ---- Path resolution -----------------------------------------------------
# Resolve a title or path to a filesystem path. Rules:
#   1. If contains '/' or has .md/.markdown/.txt extension, use as-is
#      (relative to CWD if not absolute).
#   2. Otherwise, treat as title and look in $NOTES_DIR/<title>.md
resolve_path() {
    local input="$1"
    [[ -z "$input" ]] && return 1
    if [[ "$input" == /* ]]; then
        echo "$input"
        return 0
    fi
    if [[ "$input" == *.md || "$input" == *.markdown || "$input" == *.txt ]]; then
        echo "$PWD/$input"
        return 0
    fi
    if [[ "$input" == */* ]]; then
        echo "$PWD/$input"
        return 0
    fi
    echo "$NOTES_DIR/$input.md"
}

# ---- Commands ------------------------------------------------------------
cmd_help() {
    printf "${GREEN}solomd${NC} — CLI for SoloMD Markdown Editor\n"
    printf "         %s\n\n" "https://github.com/zhitongblog/solomd"
    printf "${BLUE}USAGE${NC}\n"
    printf "  solomd <command> [args]\n\n"
    printf "${BLUE}COMMANDS${NC}\n"
    printf "  ${GREEN}%-22s${NC} %s\n" "open <title|path>" "Open file in SoloMD"
    printf "  ${GREEN}%-22s${NC} %s\n" "new <title> [text]" "Create new note + open"
    printf "  ${GREEN}%-22s${NC} %s\n" "list [folder]" "List markdown files"
    printf "  ${GREEN}%-22s${NC} %s\n" "search <query>" "Search markdown for text"
    printf "  ${GREEN}%-22s${NC} %s\n" "cat <title|path>" "Print file content"
    printf "  ${GREEN}%-22s${NC} %s\n" "export <file> -f FMT" "Export to html / md / txt / docx"
    printf "  ${GREEN}%-22s${NC} %s\n" "agent <prompt…>" "Run an LLM agent against the vault via MCP"
    printf "  ${GREEN}%-22s${NC} %s\n" "mcp-config" "Print the MCP config snippet for your AI client"
    printf "  ${GREEN}%-22s${NC} %s\n" "help" "Show this help"
    printf "\n${BLUE}NOTES DIR${NC}\n"
    printf "  ${DIM}%s${NC}\n" "$NOTES_DIR"
    printf "  ${DIM}override with SOLOMD_NOTES env var${NC}\n"
}

cmd_open() {
    local target="$1"
    [[ -z "$target" ]] && { echo "Usage: solomd open <title|path>" >&2; exit 1; }
    local path
    path="$(resolve_path "$target")"
    if [[ ! -f "$path" ]]; then
        printf "${YELLOW}File not found:${NC} %s\n" "$path" >&2
        exit 1
    fi
    local bin
    if bin="$(detect_solomd_bin)"; then
        "$bin" "$path" >/dev/null 2>&1 &
        disown 2>/dev/null || true
        printf "Opening ${GREEN}%s${NC}\n" "$path"
    elif [[ "$(uname)" == "Darwin" ]]; then
        open -a SoloMD "$path"
    else
        printf "${YELLOW}SoloMD not found.${NC} Install from https://solomd.app\n" >&2
        exit 1
    fi
}

cmd_new() {
    local title="$1"; shift || true
    local body="$*"
    [[ -z "$title" ]] && { echo "Usage: solomd new <title> [text]" >&2; exit 1; }
    ensure_notes_dir
    local path
    path="$(resolve_path "$title")"
    if [[ -f "$path" ]]; then
        printf "${YELLOW}File already exists:${NC} %s\n" "$path" >&2
        exit 1
    fi
    {
        printf "# %s\n\n" "$title"
        [[ -n "$body" ]] && printf "%s\n" "$body"
    } > "$path"
    printf "Created ${GREEN}%s${NC}\n" "$path"
    cmd_open "$path"
}

cmd_list() {
    local folder="${1:-$NOTES_DIR}"
    if [[ ! -d "$folder" ]]; then
        printf "${YELLOW}Not a folder:${NC} %s\n" "$folder" >&2
        exit 1
    fi
    find "$folder" -maxdepth 2 -type f \( -name "*.md" -o -name "*.markdown" \) 2>/dev/null \
        | sort \
        | while IFS= read -r f; do
            local rel="${f#$folder/}"
            printf "  ${GREEN}%s${NC}\n" "$rel"
        done
}

cmd_search() {
    local query="$*"
    [[ -z "$query" ]] && { echo "Usage: solomd search <query>" >&2; exit 1; }
    local folder="$NOTES_DIR"
    [[ ! -d "$folder" ]] && folder="$PWD"
    if command -v rg >/dev/null 2>&1; then
        rg --color=auto -i -t md "$query" "$folder" 2>/dev/null || {
            printf "${DIM}No matches for: %s${NC}\n" "$query"
        }
    else
        grep -ri --include="*.md" --include="*.markdown" -n "$query" "$folder" 2>/dev/null || {
            printf "${DIM}No matches for: %s${NC}\n" "$query"
        }
    fi
}

cmd_cat() {
    local target="$1"
    [[ -z "$target" ]] && { echo "Usage: solomd cat <title|path>" >&2; exit 1; }
    local path
    path="$(resolve_path "$target")"
    if [[ ! -f "$path" ]]; then
        printf "${YELLOW}File not found:${NC} %s\n" "$path" >&2
        exit 1
    fi
    cat "$path"
}

# `solomd export <file> [--format html|md|txt|docx] [--output <path>]`
# Convert a markdown file to another format using the same engine the GUI
# uses. Backs onto app/scripts/solomd-export.mjs (Node, no GUI required).
cmd_export() {
    local target="$1"; shift || true
    [[ -z "$target" ]] && {
        printf "Usage: solomd export <title|path> [--format html|md|txt|docx] [--output <path>]\n" >&2
        exit 1
    }
    local path
    path="$(resolve_path "$target")"
    if [[ ! -f "$path" ]]; then
        printf "${YELLOW}File not found:${NC} %s\n" "$path" >&2
        exit 1
    fi
    # Locate the script + the app dir (it must run with cwd = app/ so node
    # can resolve docx + markdown-it from app/node_modules without hassle).
    local repo_root script_dir app_dir
    repo_root="$(cd "$(dirname "$0")/.." && pwd)"
    app_dir="$repo_root/app"
    local script="$app_dir/scripts/solomd-export.mjs"
    if [[ ! -f "$script" ]]; then
        printf "${YELLOW}solomd-export.mjs not found at %s${NC}\n" "$script" >&2
        exit 1
    fi
    if ! command -v node >/dev/null 2>&1; then
        printf "${YELLOW}Node.js required for solomd export.${NC} Install Node 18+ (https://nodejs.org)\n" >&2
        exit 1
    fi
    if [[ ! -d "$app_dir/node_modules/docx" ]]; then
        printf "${YELLOW}app/node_modules missing. Run \`pnpm install\` in %s/app first.${NC}\n" "$repo_root" >&2
        exit 1
    fi
    (cd "$app_dir" && node "$script" "$path" "$@")
}

# ---- v3.1 agent endpoint -------------------------------------------------
# Detect the bundled solomd-mcp binary alongside the desktop app, falling
# back to anything on PATH. We don't ship a separate sidecar yet — the
# desktop app embeds it via tauri externalBin, so the lookup mirrors
# detect_solomd_bin().
detect_mcp_bin() {
    if [[ "$(uname)" == "Darwin" ]]; then
        local mac_paths=(
            "/Applications/SoloMD.app/Contents/Resources/solomd-mcp"
            "$HOME/Applications/SoloMD.app/Contents/Resources/solomd-mcp"
        )
        for p in "${mac_paths[@]}"; do
            [[ -x "$p" ]] && echo "$p" && return 0
        done
    elif [[ "$(uname)" == "Linux" ]]; then
        local linux_paths=(
            "/usr/lib/solomd/solomd-mcp"
            "/usr/local/lib/solomd/solomd-mcp"
            "/opt/SoloMD/solomd-mcp"
        )
        for p in "${linux_paths[@]}"; do
            [[ -x "$p" ]] && echo "$p" && return 0
        done
    fi
    if command -v solomd-mcp >/dev/null 2>&1; then
        command -v solomd-mcp
        return 0
    fi
    return 1
}

cmd_mcp_config() {
    local mcp_bin
    if ! mcp_bin="$(detect_mcp_bin)"; then
        printf "${YELLOW}solomd-mcp not found.${NC} Install SoloMD or run install-mcp.sh.\n" >&2
        printf "${DIM}https://github.com/zhitongblog/solomd/blob/main/scripts/install-mcp.sh${NC}\n" >&2
        exit 1
    fi
    local workspace="${SOLOMD_NOTES:-$HOME/Documents/SoloMD}"
    cat <<EOF
{
  "mcpServers": {
    "solomd": {
      "command": "$mcp_bin",
      "args": ["--workspace", "$workspace"]
    }
  }
}
EOF
}

# `solomd agent <prompt>` — hand the prompt off to whichever LLM CLI is on
# PATH (claude / codex / aider), with solomd-mcp pre-wired. We deliberately
# do not implement an LLM loop ourselves: the user already has Claude Code,
# Codex CLI, or aider installed and configured with their BYOK keys. Our
# job is to put a SoloMD MCP server in front of that CLI so it can read +
# edit the vault, then pass through.
cmd_agent() {
    local prompt="$*"
    [[ -z "$prompt" ]] && {
        printf "Usage: solomd agent <prompt>\n" >&2
        printf "  e.g. solomd agent 'rewrite this week of dailies into a weekly review'\n" >&2
        exit 1
    }

    local mcp_bin
    if ! mcp_bin="$(detect_mcp_bin)"; then
        printf "${YELLOW}solomd-mcp not found.${NC}\n" >&2
        printf "  SoloMD bundles solomd-mcp inside the app (Mac/Linux). Make sure SoloMD is installed,\n" >&2
        printf "  or run scripts/install-mcp.sh from this repo to drop it on PATH.\n" >&2
        exit 1
    fi
    local workspace="${SOLOMD_NOTES:-$HOME/Documents/SoloMD}"

    # Generate a one-shot MCP config in TMPDIR so the LLM CLI can pick it
    # up without us touching the user's persistent config.
    local cfg_dir
    cfg_dir="$(mktemp -d -t solomd-agent.XXXXXX)"
    local cfg="$cfg_dir/mcp.json"
    cat > "$cfg" <<EOF
{
  "mcpServers": {
    "solomd": {
      "command": "$mcp_bin",
      "args": ["--workspace", "$workspace", "--allow-write"]
    }
  }
}
EOF
    trap "rm -rf $cfg_dir" EXIT

    printf "${DIM}vault:    %s${NC}\n" "$workspace"
    printf "${DIM}mcp:      %s${NC}\n" "$mcp_bin"

    if command -v claude >/dev/null 2>&1; then
        printf "${BLUE}→ claude${NC} (Claude Code CLI)\n\n"
        # `claude "query"` starts an interactive session seeded with the
        # query. `--mcp-config` registers the SoloMD MCP for that session.
        # We don't pass `-p` (non-interactive one-shot) by default — agent
        # work usually needs follow-up turns.
        exec claude --mcp-config "$cfg" -- "$prompt"
    elif command -v codex >/dev/null 2>&1; then
        printf "${BLUE}→ codex${NC} (Codex CLI)\n\n"
        # Codex CLI registers MCP servers via ~/.codex/config.toml, not a
        # CLI flag. Print the right snippet and run codex with the prompt.
        printf "${DIM}Add this to ~/.codex/config.toml if not already present:${NC}\n"
        printf "  [mcp_servers.solomd]\n"
        printf "  command = \"%s\"\n" "$mcp_bin"
        printf "  args = [\"--workspace\", \"%s\", \"--allow-write\"]\n\n" "$workspace"
        exec codex "$prompt"
    elif command -v aider >/dev/null 2>&1; then
        printf "${BLUE}→ aider${NC} (no native MCP — printing recipe instead)\n\n"
        printf "  The aider CLI doesn't speak MCP. Either:\n"
        printf "  1. Install Claude Code: https://docs.claude.com/en/docs/claude-code\n"
        printf "  2. Or run: aider %s\n" "$workspace"
        printf "     (it will read+edit notes directly without the SoloMD MCP wrapper)\n"
        exit 0
    else
        printf "${YELLOW}No supported LLM CLI found on PATH.${NC}\n\n" >&2
        printf "  Install one of:\n" >&2
        printf "    Claude Code  — https://docs.claude.com/en/docs/claude-code\n" >&2
        printf "    Codex CLI    — https://github.com/openai/codex\n" >&2
        printf "  Then re-run: solomd agent '$prompt'\n\n" >&2
        printf "${DIM}MCP config that would be used:${NC}\n" >&2
        cat "$cfg" >&2
        exit 1
    fi
}

# ---- Dispatch ------------------------------------------------------------
case "${1:-help}" in
    open)       shift; cmd_open "$@" ;;
    new)        shift; cmd_new "$@" ;;
    list)       shift; cmd_list "$@" ;;
    search)     shift; cmd_search "$@" ;;
    cat)        shift; cmd_cat "$@" ;;
    export)     shift; cmd_export "$@" ;;
    agent)      shift; cmd_agent "$@" ;;
    mcp-config) shift; cmd_mcp_config "$@" ;;
    help|--help|-h) cmd_help ;;
    *) printf "${YELLOW}Unknown command:${NC} %s\n\n" "$1"; cmd_help; exit 1 ;;
esac
