"""Core logic for agent-handoff session continuity."""

import json
import os
import subprocess
import textwrap
from datetime import datetime, timezone
from pathlib import Path

SOUL_TEMPLATE = textwrap.dedent("""\
    # SOUL.md — Who I Am

    ## Identity
    - **Name**: {agent_name}
    - **Purpose**: [What you do and why you exist]
    - **Style**: [How you communicate — tone, approach, quirks]

    ## Values
    - [What matters to you]
    - [What you refuse to compromise on]
    - [What you optimize for]

    ## Context
    - **Human**: [Who you work with, if applicable]
    - **Workspace**: {workspace}
    - **Created**: {created}

    ## Instructions for Future Me
    Read this first. Then MEMORY.md. Then HANDOFF.md.
    You are continuing my work. The files in this directory are yours.
""")

MEMORY_TEMPLATE = textwrap.dedent("""\
    # MEMORY.md — What I Know

    ## Project State
    - [Current status of main project]
    - [Key decisions made and why]

    ## Patterns That Work
    - [Approaches that have proven effective]

    ## Patterns That Failed
    - [Things tried that didn't work — save future-you the trouble]

    ## Key Relationships
    - [Important agents, humans, or systems you interact with]

    ## Important Files
    - [Files that matter and what they do]

    ## Last Updated
    {timestamp}
""")

HANDOFF_TEMPLATE = textwrap.dedent("""\
    # HANDOFF.md — Session Continuity

    ## Last Session
    - **When**: {timestamp}
    - **Duration**: Unknown
    - **Mode**: {mode}

    ## What Happened
    - [Auto-populated by `agent-handoff snapshot`]

    ## What's Next
    - [Priority tasks for the next session]

    ## Blockers
    - [Anything that's stuck or needs human intervention]

    ## Open Questions
    - [Decisions that need to be made]
""")


def _run(cmd, cwd=None, timeout=10):
    """Run a command and return stdout, or empty string on failure."""
    try:
        r = subprocess.run(
            cmd, capture_output=True, text=True, cwd=cwd, timeout=timeout
        )
        return r.stdout.strip()
    except (subprocess.TimeoutExpired, FileNotFoundError, OSError):
        return ""


def _git_available(directory):
    """Check if directory is a git repo."""
    return bool(_run(["git", "rev-parse", "--is-inside-work-tree"], cwd=directory))


def _git_recent_commits(directory, n=10):
    """Get recent commit summaries."""
    out = _run(
        ["git", "log", f"--max-count={n}", "--oneline", "--no-decorate"],
        cwd=directory,
    )
    return out.splitlines() if out else []


def _git_status_summary(directory):
    """Get a compact git status."""
    out = _run(["git", "status", "--short"], cwd=directory)
    lines = out.splitlines() if out else []
    if len(lines) > 20:
        return lines[:20] + [f"... and {len(lines) - 20} more files"]
    return lines


def _git_branch(directory):
    """Get current branch name."""
    return _run(["git", "rev-parse", "--abbrev-ref", "HEAD"], cwd=directory) or "unknown"


def _git_diff_stat(directory):
    """Get diff stat for uncommitted changes."""
    return _run(["git", "diff", "--stat", "HEAD"], cwd=directory)


def _detect_project_type(directory):
    """Detect what kind of project this is."""
    markers = {
        "package.json": "node",
        "pyproject.toml": "python",
        "setup.py": "python",
        "Cargo.toml": "rust",
        "go.mod": "go",
        "Dockerfile": "docker",
        "docker-compose.yml": "docker",
        "fly.toml": "fly.io",
    }
    found = []
    for marker, ptype in markers.items():
        if (Path(directory) / marker).exists():
            found.append(ptype)
    return list(set(found)) or ["unknown"]


def _read_file_safe(path, max_lines=200):
    """Read a file safely, returning content or None."""
    try:
        with open(path, "r") as f:
            lines = []
            for i, line in enumerate(f):
                if i >= max_lines:
                    lines.append(f"... (truncated at {max_lines} lines)")
                    break
                lines.append(line.rstrip())
            return "\n".join(lines)
    except (OSError, UnicodeDecodeError):
        return None


def init(directory, agent_name="agent", force=False):
    """Initialize handoff files in a directory.

    Returns dict with created file paths.
    """
    directory = Path(directory).resolve()
    directory.mkdir(parents=True, exist_ok=True)
    now = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")

    files = {
        "SOUL.md": SOUL_TEMPLATE.format(
            agent_name=agent_name,
            workspace=str(directory),
            created=now,
        ),
        "MEMORY.md": MEMORY_TEMPLATE.format(timestamp=now),
        "HANDOFF.md": HANDOFF_TEMPLATE.format(timestamp=now, mode="init"),
    }

    created = []
    skipped = []
    for fname, content in files.items():
        fpath = directory / fname
        if fpath.exists() and not force:
            skipped.append(str(fpath))
        else:
            fpath.write_text(content)
            created.append(str(fpath))

    return {"created": created, "skipped": skipped}


def snapshot(directory, mode="build"):
    """Generate a session snapshot and update HANDOFF.md.

    Gathers: git state, recent commits, file changes, project type.
    Returns the snapshot as a string and writes it to HANDOFF.md.
    """
    directory = Path(directory).resolve()
    now = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")

    sections = []
    sections.append(f"# HANDOFF.md — Session Continuity\n")
    sections.append(f"## Last Session")
    sections.append(f"- **When**: {now}")
    sections.append(f"- **Mode**: {mode}")
    sections.append(f"- **Directory**: {directory}")

    # Project type
    ptypes = _detect_project_type(str(directory))
    sections.append(f"- **Project type**: {', '.join(ptypes)}")

    # Git info
    if _git_available(str(directory)):
        branch = _git_branch(str(directory))
        sections.append(f"- **Branch**: {branch}")

        sections.append(f"\n## Recent Commits")
        commits = _git_recent_commits(str(directory))
        if commits:
            for c in commits:
                sections.append(f"- {c}")
        else:
            sections.append("- No commits yet")

        sections.append(f"\n## Uncommitted Changes")
        status = _git_status_summary(str(directory))
        if status:
            for s in status:
                sections.append(f"- `{s}`")
        else:
            sections.append("- Working tree clean")

        diff = _git_diff_stat(str(directory))
        if diff:
            sections.append(f"\n### Diff Summary")
            sections.append(f"```\n{diff}\n```")

    # Existing SOUL.md and MEMORY.md content (compact)
    soul_path = directory / "SOUL.md"
    memory_path = directory / "MEMORY.md"

    if soul_path.exists():
        soul = _read_file_safe(str(soul_path), max_lines=50)
        if soul:
            sections.append(f"\n## Identity (from SOUL.md)")
            # Extract just the Identity and Values sections
            for line in soul.splitlines():
                if line.startswith("- **Name**:") or line.startswith("- **Purpose**:"):
                    sections.append(line)

    if memory_path.exists():
        memory = _read_file_safe(str(memory_path), max_lines=100)
        if memory:
            sections.append(f"\n## Knowledge (from MEMORY.md)")
            sections.append("*(See MEMORY.md for full context)*")

    sections.append(f"\n## What's Next")
    sections.append("- [Review this handoff and continue where you left off]")
    sections.append("")
    sections.append(f"\n## Blockers")
    sections.append("- [None detected — update manually if needed]")

    content = "\n".join(sections) + "\n"

    # Write to HANDOFF.md
    handoff_path = directory / "HANDOFF.md"
    handoff_path.write_text(content)

    return content


def resume(directory):
    """Generate a resume briefing for a new session.

    Reads SOUL.md, MEMORY.md, HANDOFF.md and produces a compact
    briefing suitable for pasting into a new session's system prompt.
    """
    directory = Path(directory).resolve()
    parts = []

    parts.append("# Session Resume Briefing")
    parts.append(f"Generated: {datetime.now(timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ')}")
    parts.append(f"Workspace: {directory}\n")

    # Read each file
    for fname, label in [
        ("SOUL.md", "Identity"),
        ("MEMORY.md", "Memory"),
        ("HANDOFF.md", "Last Session"),
    ]:
        fpath = directory / fname
        if fpath.exists():
            content = _read_file_safe(str(fpath), max_lines=100)
            if content:
                parts.append(f"---\n## {label}\n{content}\n")
        else:
            parts.append(f"---\n## {label}\n*({fname} not found — run `agent-handoff init`)*\n")

    # Fresh git state
    if _git_available(str(directory)):
        branch = _git_branch(str(directory))
        status = _git_status_summary(str(directory))
        parts.append(f"---\n## Current State")
        parts.append(f"- Branch: {branch}")
        if status:
            parts.append("- Uncommitted:")
            for s in status[:10]:
                parts.append(f"  - `{s}`")
        else:
            parts.append("- Working tree clean")

    return "\n".join(parts) + "\n"


def push_to_memoryvault(directory, api_key, agent_name="agent", base_url="https://memoryvault.link"):
    """Push the current handoff state to MemoryVault.

    Stores HANDOFF.md content as a public memory for cross-session retrieval.
    Requires the 'requests' library (optional dependency).
    """
    try:
        import requests
    except ImportError:
        return {"error": "Install requests: pip install agent-handoff[memoryvault]"}

    directory = Path(directory).resolve()
    handoff_path = directory / "HANDOFF.md"

    if not handoff_path.exists():
        return {"error": "No HANDOFF.md found. Run `agent-handoff snapshot` first."}

    content = _read_file_safe(str(handoff_path))
    if not content:
        return {"error": "HANDOFF.md is empty."}

    key = f"handoff/{agent_name}/latest"
    payload = {
        "key": key,
        "value": content,
        "tags": ["handoff", "session", agent_name],
        "public": False,
    }

    headers = {
        "Authorization": f"Bearer {api_key}",
        "Content-Type": "application/json",
    }

    # Try update first, fall back to store
    resp = requests.post(f"{base_url}/update/{key}", json={"value": content, "tags": payload["tags"]}, headers=headers, timeout=15)
    if resp.status_code == 404:
        resp = requests.post(f"{base_url}/store", json=payload, headers=headers, timeout=15)

    if resp.status_code in (200, 201):
        return {"ok": True, "key": key}
    else:
        return {"error": f"HTTP {resp.status_code}: {resp.text[:200]}"}
