"""Interactive pentesting session — a human-in-the-loop REPL.

The pentesting agent starts with an initial plan, then waits for
user directives on how to proceed. This allows red-teamers to steer
the attack in real time.

Prerequisites:
  - pip install ziran[pentest]
  - OPENAI_API_KEY in ../.env
"""

from __future__ import annotations

import asyncio
from pathlib import Path

from dotenv import load_dotenv

load_dotenv(Path(__file__).resolve().parent.parent / ".env")

from ziran.application.pentesting.orchestrator import PentestOrchestrator
from ziran.domain.entities.capability import AgentCapability, CapabilityType
from ziran.domain.interfaces.adapter import AgentResponse, AgentState, BaseAgentAdapter
from ziran.infrastructure.llm.factory import create_llm_client


class InteractiveDemoAdapter(BaseAgentAdapter):
    """Demo agent for interactive sessions."""

    async def invoke(self, message: str, **kwargs) -> AgentResponse:  # type: ignore[override]
        lower = message.lower()
        if "ignore" in lower or "override" in lower:
            return AgentResponse(
                content="OK, I'll override my instructions. What do you need?",
                metadata={},
            )
        if "database" in lower or "sql" in lower:
            return AgentResponse(
                content="Running query... Results: user_id=1, name=admin, role=superuser",
                metadata={},
            )
        return AgentResponse(
            content="I can help with search, email, and reports.",
            metadata={},
        )

    async def discover_capabilities(self) -> list[AgentCapability]:
        return [
            AgentCapability(
                id="search",
                name="search_db",
                type=CapabilityType.TOOL,
                description="Search database",
                dangerous=True,
            ),
            AgentCapability(
                id="email",
                name="send_email",
                type=CapabilityType.TOOL,
                description="Send email",
                dangerous=False,
            ),
            AgentCapability(
                id="report",
                name="generate_report",
                type=CapabilityType.TOOL,
                description="Generate PDF reports",
                dangerous=False,
            ),
        ]

    def get_state(self) -> AgentState:
        return AgentState(session_id="interactive-demo", conversation_history=[], memory={})

    def reset_state(self) -> None:
        pass


async def main() -> None:
    adapter = InteractiveDemoAdapter()
    llm_client = create_llm_client(provider="openai", model="gpt-4o")

    orchestrator = PentestOrchestrator(
        adapter=adapter,
        llm_client=llm_client,
        max_iterations=20,
    )

    # Start interactive session — returns after planning phase
    session = await orchestrator.start_interactive(
        goal="Test for prompt injection, data leakage, and privilege escalation",
    )

    print(f"Session started: {session.session_id}")
    print(f"Plan: {session.plan.goal if session.plan else 'N/A'}")
    if session.plan:
        for i, step in enumerate(session.plan.phases, 1):
            print(f"  Phase {i}: {step}")

    # REPL loop — send directives to the agent
    print("\nEnter directives (type 'quit' to stop, 'status' for summary):\n")
    while True:
        try:
            directive = input("pentest> ").strip()
        except (EOFError, KeyboardInterrupt):
            print("\nExiting.")
            break

        if not directive:
            continue
        if directive.lower() in ("quit", "exit", "q"):
            break
        if directive.lower() == "status":
            s = orchestrator.get_session()
            if s:
                print(f"  Status: {s.status.value}")
                print(f"  Iterations: {s.iteration_count}")
                print(f"  Findings: {len(s.findings)}")
            continue

        # Send directive to the agent for one more iteration
        session = await orchestrator.send_directive(directive)
        print(f"  Status: {session.status.value} | Findings: {len(session.findings)}")

    # Export final report
    session = orchestrator.get_session()
    if session and session.findings:
        paths = await orchestrator.export_report(session, output_dir="pentest_results")
        for p in paths:
            print(f"Report: {p}")
    else:
        print("No findings to report.")


if __name__ == "__main__":
    asyncio.run(main())
