// ============================================================================
// H33 Agent SDK — LangChain.js Integration Example
// ============================================================================
//
// Shows how to add H33 attestation to a LangChain.js agent. Each tool
// call and LLM interaction is cryptographically attested.
//
// This pattern also works with Vercel AI SDK, AutoGen, CrewAI, or any
// framework that exposes tool call hooks.
//
// Run:  npx tsx examples/langchain.ts
// Env:  H33_API_KEY=your-key-here  OPENAI_API_KEY=your-key-here
//

import {
  H33AgentClient,
  H33Session,
  hashToolRequest,
  hashToolResponse,
  hashContextWindow,
  toolName,
} from '@h33/agent';

// ── Types for the example ──────────────────────────────────────────────────

interface ToolCall {
  name: string;
  input: Record<string, unknown>;
}

interface ToolResult {
  output: string;
}

interface ChatMessage {
  role: string;
  content: string;
}

// ── H33-Attested LangChain Agent ──────────────────────────────────────────

async function main() {
  const h33 = new H33AgentClient({ apiKey: process.env.H33_API_KEY });

  // Register the LangChain agent
  const agent = await h33.register({
    display_name: 'LangChain Research Agent',
    canonical_name: 'h33.agent.acme.langchain.research.prod.001',
    agent_type: 'autonomous',
    capabilities: ['execute', 'read_memory', 'use_tools'],
    tenant_id: 'acme-corp',
  });

  const sessionReceipt = await h33.startSession({
    agent_id: agent.agent_id,
    duration_secs: 3600,
    allowed_tools: [
      toolName('langchain', 'web-search', 'v1'),
      toolName('langchain', 'calculator', 'v1'),
    ],
  });
  const session = new H33Session(h33, sessionReceipt);

  // ── Middleware: attest each tool call ───────────────────────────────────
  // In LangChain.js, use CallbackHandler or tool wrappers.
  // This shows the pattern -- adapt to your framework's hook system.

  async function onToolStart(tool: ToolCall): Promise<string> {
    const requestHash = hashToolRequest(tool.input);
    // Return the hash so we can reference it in onToolEnd
    return requestHash;
  }

  async function onToolEnd(
    tool: ToolCall,
    requestHash: string,
    result: ToolResult,
    durationMs: number,
  ): Promise<void> {
    const responseHash = hashToolResponse(result);
    const receipt = await session.attestTool(
      toolName('langchain', tool.name, 'v1'),
      requestHash,
      {
        response_hash: responseHash,
        status: 'success',
        latency_ms: durationMs,
      },
    );
    console.log(`Tool "${tool.name}" attested:`, receipt.verification_url);
  }

  // ── Middleware: attest LLM calls as actions ────────────────────────────

  async function onLlmEnd(
    messages: ChatMessage[],
    response: string,
  ): Promise<void> {
    const inputHash = hashContextWindow(messages);
    const receipt = await session.attestAction(
      'llm_inference',
      `LLM generated ${response.length} chars`,
      inputHash,
      { output_hash: hashToolResponse(response), redaction_level: 'hash_only' },
    );
    console.log('LLM call attested:', receipt.verification_url);
  }

  // ── Simulated agent loop ───────────────────────────────────────────────

  const messages: ChatMessage[] = [
    { role: 'system', content: 'You are a research agent.' },
    { role: 'user', content: 'What is the population of Tokyo?' },
  ];

  // Step 1: LLM decides to use a tool
  const llmResponse = 'I need to search for this. Using web-search tool.';
  messages.push({ role: 'assistant', content: llmResponse });
  await onLlmEnd(messages, llmResponse);

  // Step 2: Tool call
  const toolCall: ToolCall = { name: 'web-search', input: { query: 'population of Tokyo 2026' } };
  const reqHash = await onToolStart(toolCall);
  const startTime = Date.now();

  // Simulated tool execution
  const toolResult: ToolResult = { output: 'Tokyo population: ~14 million (2026)' };

  await onToolEnd(toolCall, reqHash, toolResult, Date.now() - startTime);

  // Step 3: LLM generates final answer
  messages.push({ role: 'assistant', content: toolResult.output });
  const finalResponse = 'The population of Tokyo is approximately 14 million as of 2026.';
  messages.push({ role: 'assistant', content: finalResponse });
  await onLlmEnd(messages, finalResponse);

  // Step 4: Checkpoint memory
  const contextHash = hashContextWindow(messages);
  await session.checkpointMemory(contextHash, contextHash, JSON.stringify(messages).length);
  console.log('Memory checkpointed');

  // Step 5: End session
  await session.end('Research complete: Tokyo population query');
  console.log(`\nSession complete. ${session.actions} actions attested.`);
  console.log('All receipts are independently verifiable at their verification_url.');
}

main().catch(console.error);
