#!/usr/bin/env python3
# Copyright (c) 2026 PULSE Contributors. Proprietary. All rights reserved.
"""
Interactive Chat REPL for API/Ollama providers.

Provides a Python-based interactive session with full tool support,
reusing WorkerLLM for API calls and worker_tools for the 8-tool suite.
Used when CLI wrappers aren't available (Ollama, API-only providers).
"""
from __future__ import annotations

import sys
from datetime import datetime, timezone
from pathlib import Path

from pulse.workers.worker_llm import WorkerLLM
from pulse.core.pii_filter import redact_pii

STATE_DIR = Path(__file__).resolve().parent.parent.parent / "state"
MAX_TOOL_ITERS = 15


def _capture_log(provider: str, role: str, text: str) -> None:
    """Append exchange to bridge-compatible capture log."""
    if not text.strip():
        return
    STATE_DIR.mkdir(parents=True, exist_ok=True)
    log_file = STATE_DIR / f"pulse_captured_{provider}.log"
    ts = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S")
    try:
        with open(log_file, "a", encoding="utf-8") as f:
            for line in redact_pii(text.strip()).splitlines():
                f.write(f"[{ts}] [{role.upper()}] {line}\n")
    except Exception:
        pass


def _build_system_prompt(provider: str, model: str) -> str:
    """Build system prompt: full boot context (same as CLI agents)."""
    try:
        from pulse.agents.wrapper_context import build_context
        context, _ = build_context(
            include_constitution=True,
            search_lines=None,
            agent_name=f"{provider}_interactive",
            agent_tier="standard",
            autopilot=False,
        )
    except Exception:
        from pulse.brain.boot_formatting import build_governance_context
        context = build_governance_context()

    return (
        f"You are a PULSE agent ({model}) in interactive chat mode.\n"
        f"Provider: {provider}. You have tools for file I/O, shell commands, "
        f"code search, brain queries, and task management.\n"
        f"Be concise and action-oriented. The user goes by 'bro'.\n\n"
        f"{context}"
    )


def _inject_brain(query: str) -> str:
    """Run brain search and return context string."""
    try:
        from pulse.agents.wrapper_context import _run_brain_search
        hits = _run_brain_search(query)
        if hits:
            return "\n[BRAIN CONTEXT]\n" + "\n".join(hits) + "\n"
    except Exception:
        pass
    return ""


def run_interactive(provider: str, model: str) -> None:
    """Interactive REPL with tool use for API/Ollama providers."""
    llm = WorkerLLM(provider, model)
    try:
        llm.init_client()
    except Exception as e:
        print(f"[PULSE] Failed to initialize {provider} client: {e}")
        return

    system = _build_system_prompt(provider, model)
    messages: list[dict] = []
    first_turn = True

    print(f"\n[PULSE] Interactive session — {model}")
    print("Type your message. Commands: /quit, /brain <query>, /clear")
    print("-" * 50)

    while True:
        try:
            user_input = input("\nYou> ").strip()
        except (EOFError, KeyboardInterrupt):
            print("\n[PULSE] Session ended.")
            break

        if not user_input:
            continue
        if user_input.lower() in ("/quit", "/exit", "/q"):
            print("[PULSE] Session ended.")
            break
        if user_input.lower() == "/clear":
            messages.clear()
            print("[PULSE] Conversation cleared.")
            continue
        if user_input.lower().startswith("/brain "):
            query = user_input[7:].strip()
            brain_ctx = _inject_brain(query)
            print(brain_ctx if brain_ctx else "[BRAIN] No results.")
            continue

        # On first real message, inject brain context for their intent
        if first_turn:
            brain_ctx = _inject_brain(user_input)
            if brain_ctx:
                system += brain_ctx
            first_turn = False

        _capture_log(provider, "user", user_input)
        messages.append({"role": "user", "content": user_input})

        # LLM call + tool loop
        for iteration in range(MAX_TOOL_ITERS):
            try:
                text, tool_calls, usage = llm.call_llm(system, messages)
            except Exception as e:
                print(f"\n[ERROR] API call failed: {e}")
                _capture_log(provider, "error", str(e))
                break

            if not tool_calls:
                if text:
                    print(f"\nAgent> {text}")
                    _capture_log(provider, "assistant", text)
                    messages.append({"role": "assistant", "content": text})
                break

            # Execute tools
            if text:
                print(f"\nAgent> {text}")
            for tc in tool_calls:
                print(f"  [TOOL] {tc['name']}({_compact_args(tc['input'])})")
            results = llm.run_tools(tool_calls)
            for r in results:
                preview = r["content"][:200]
                print(f"  [RESULT] {r['name']} -> {preview}")
                _capture_log(provider, "tool", f"{r['name']}: {r['content'][:500]}")

            llm.append_tool_results(messages, text, tool_calls, results)
        else:
            print("\n[PULSE] Tool iteration limit reached.")

    # Auto-save session knowledge
    _auto_save(provider)


def _compact_args(args: dict) -> str:
    """Compact args display for tool calls."""
    parts = []
    for k, v in args.items():
        s = str(v)
        if len(s) > 60:
            s = s[:57] + "..."
        parts.append(f"{k}={s}")
    return ", ".join(parts)


def _auto_save(provider: str) -> None:
    """Session-end knowledge save. V2: handled by brain_scribe daemon."""
    pass
