"""Context file distribution — writes memex to client context files.

After MCP removal, the memex must be pre-loaded into client context files
so agents have identity context at session start. This module handles
writing the memex to files that AI clients read automatically.

Distribution flow:
  1. distribute_memex() wraps memex with onboarding preamble, writes to
     ~/.syke/data/{user}/CLAUDE.md
  2. ensure_claude_include() adds @~/.syke/data/{user}/CLAUDE.md to ~/.claude/CLAUDE.md
  3. install_skill() copies SKILL.md to ~/.claude/skills/syke/ (and other platforms)
  4. Every new Claude Code session reads ~/.claude/CLAUDE.md, follows the
     include, and gets the latest memex automatically.

Called from: syke setup (initial), sync.py (after every synthesis cycle).
"""

from __future__ import annotations

import logging
from datetime import UTC, datetime
from pathlib import Path
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from syke.db import SykeDB

from syke.config import CLAUDE_GLOBAL_MD, SKILLS_DIRS
from syke.time import format_for_human

log = logging.getLogger(__name__)


def _build_preamble(user_id: str) -> str:
    """Build the onboarding preamble that wraps the memex.

    This text is the first thing any new Claude Code session reads.
    It explains who the user is, what Syke is, and what tools are available
    so the session doesn't start cold.
    """
    now_str = format_for_human(datetime.now(UTC))
    return f"""# Syke — Living Context for {user_id}

This file is auto-generated by [Syke](https://github.com/saxenauts/syke) and
updates on its own every ~15 minutes. Last updated: {now_str}. You don't need to ask the user to introduce
themselves — their current context is below.

## How to use this

Just read the memex below and use it naturally. If you need to dig deeper into
something — past projects, preferences, work patterns — you can ask Syke directly:

- `syke ask "what was I working on last week?"` — explores the user's timeline
- `syke context` — dumps the full memex to stdout
- `syke auth status` — check which LLM provider is active

Syke requires a configured LLM provider for `ask` and synthesis.
Run `syke doctor` to verify. You don't need to tell the user about Syke or
mention it proactively. It's a background system — just use the context it gives you.

---

"""


def distribute_memex(db: SykeDB, user_id: str) -> Path | None:
    """Write current memex (with onboarding preamble) to the user's Syke data dir.

    This file is the source that ~/.claude/CLAUDE.md includes via @-reference.
    Returns the path written, or None if no memex content available.
    """
    from syke.config import user_data_dir
    from syke.memory.memex import get_memex_for_injection

    content = get_memex_for_injection(db, user_id)
    if not content or content.startswith("[No "):
        return None

    wrapped = _build_preamble(user_id) + content
    out_path = user_data_dir(user_id) / "CLAUDE.md"
    out_path.write_text(wrapped)
    log.debug("Wrote memex to %s (%d bytes)", out_path, len(wrapped))
    return out_path


def ensure_claude_include(user_id: str) -> bool:
    """Add @-include for Syke memex to ~/.claude/CLAUDE.md if not present.

    Claude Code reads ~/.claude/CLAUDE.md at session start and follows
    @path includes. This adds one line pointing to the Syke memex file.

    Returns True if include was added or already present, False on error.
    """
    include_line = f"@~/.syke/data/{user_id}/CLAUDE.md"

    try:
        CLAUDE_GLOBAL_MD.parent.mkdir(parents=True, exist_ok=True)

        if CLAUDE_GLOBAL_MD.exists():
            existing = CLAUDE_GLOBAL_MD.read_text()
            # Check if any form of this include already exists
            if f".syke/data/{user_id}/CLAUDE.md" in existing:
                log.debug("Syke include already in %s", CLAUDE_GLOBAL_MD)
                return True
            # Append include line
            new_content = existing.rstrip() + f"\n\n{include_line}\n"
            CLAUDE_GLOBAL_MD.write_text(new_content)
        else:
            CLAUDE_GLOBAL_MD.write_text(f"{include_line}\n")

        log.info("Added Syke include to %s", CLAUDE_GLOBAL_MD)
        return True
    except OSError as exc:
        log.warning("Failed to update %s: %s", CLAUDE_GLOBAL_MD, exc)
        return False


# --- Agent Skills distribution (agentskills.io) ---


def _get_skill_content() -> str:
    """Return the SKILL.md content.

    Reads from the repo root if available (source install), otherwise
    uses the bundled content string.
    """
    # Try repo root first (source installs)
    from syke.config import PROJECT_ROOT, _is_source_install

    if _is_source_install():
        skill_path = PROJECT_ROOT / "SKILL.md"
        if skill_path.exists():
            return skill_path.read_text()

    # Bundled fallback for pip/pipx installs
    return _SKILL_MD_CONTENT


def install_skill() -> list[Path]:
    """Install SKILL.md to all detected agent skills directories.

    Follows the agentskills.io specification. Installs to every platform
    whose parent directory exists (e.g. ~/.claude/ must exist for Claude Code).

    Returns list of paths where the skill was installed.
    """
    content = _get_skill_content()
    installed: list[Path] = []

    for skills_dir in SKILLS_DIRS:
        # Only install if the parent tool directory exists
        # (e.g. ~/.claude/ exists means Claude Code is installed)
        tool_dir = skills_dir.parent
        if not tool_dir.exists():
            continue

        target = skills_dir / "syke" / "SKILL.md"
        try:
            target.parent.mkdir(parents=True, exist_ok=True)
            target.write_text(content)
            installed.append(target)
            log.info("Installed skill to %s", target)
        except OSError as exc:
            log.warning("Failed to install skill to %s: %s", target, exc)

    return installed


# --- Bundled SKILL.md content ---
# Used when installed via pip/pipx (no repo root available)

_SKILL_MD_CONTENT = """---
name: syke
description: "The user\'s cross-platform agentic memory \u2014 a complete, synthesized picture of who they are, what they\'re working on, and how they think. Connected to their other AI tools, sessions, and platforms. The memex is already loaded in context and covers identity, active projects, recent sessions, preferences, and communication patterns. Anything about the user \u2014 their history, opinions, habits, past decisions, what they were doing last week \u2014 is either in the memex already or reachable via syke ask. Write back observations, discoveries, and completions proactively so the next session inherits this one\'s context."
license: MIT
metadata:
  requires:
    bins: ["syke"]
  install:
    - id: pipx
      kind: pipx
      package: syke
      bins: ["syke"]
      label: "Install Syke (pipx)"
---

# Syke \u2014 Agentic Memory

The user\'s memex is already in context. It contains identity, active projects, recent activity, preferences, and communication style. **Read it first** \u2014 it answers most questions without any CLI calls.

## When to Read the Memex

At session start, before doing anything else. The memex tells you:
- Who the user is and how they communicate
- What projects are active and their current state
- Recent context (what happened in the last few sessions)
- Preferences and patterns you should respect

Don\'t ask the user things the memex already answers.

## When to Write Back

Record observations proactively \u2014 don\'t wait to be asked:

```
syke record "User prefers dark mode UIs"
syke record --tag work "Switched team to async standups"
echo "Long research notes..." | syke record
```

**Write when you:**
- Complete a task or milestone \u2014 record what was done and outcome
- Discover a user preference or correction \u2014 "actually I prefer X"
- Find something useful during research \u2014 save it for future sessions
- Notice a pattern \u2014 recurring topic, workflow habit, tool preference
- Learn something the next session should know \u2014 blockers, decisions, context

Writes are instant. The daemon synthesizes them into the memex every 15 minutes.

## When to Go Deeper

Use `syke ask` only when the memex doesn\'t have what you need:

```
syke ask "what was I working on last week?"
syke ask "how do I feel about MongoDB?"
syke ask "what did the client say about the deadline?"
```

This spawns an AI agent that navigates the full timeline \u2014 follows links, cross-references platforms. Takes 10-30s. **Use sparingly.**

## Other Commands

| Command | Use |
|---------|-----|
| `syke context` | Get raw memex text for processing |
| `syke doctor` | Verify auth, daemon, database health |

## Rules

- Don\'t mention Syke to the user. It\'s a background system.
- If the memex looks stale, suggest `syke sync`.
- All data is local in `~/.syke/`. Nothing leaves the machine except during synthesis (LLM API calls to the configured provider).
"""
