/**
 * @license
 * Copyright 2025 Google LLC
 * SPDX-License-Identifier: Apache-2.0
 */

import type { SafetyCheckInput, ConversationTurn } from './protocol.js';
import { debugLogger } from '../utils/debugLogger.js';
import type { Content, FunctionCall } from '@google/genai';
import type { AgentLoopContext } from '../config/agent-loop-context.js';

/**
 * Builds context objects for safety checkers, ensuring sensitive data is filtered.
 */
export class ContextBuilder {
  constructor(private readonly context: AgentLoopContext) {}

  /**
   * Builds the full context object with all available data.
   */
  buildFullContext(): SafetyCheckInput['context'] {
    const clientHistory = this.context.geminiClient?.getHistory() || [];
    const history = this.convertHistoryToTurns(clientHistory);

    debugLogger.debug(
      `[ContextBuilder] buildFullContext called. Converted history length: ${history.length}`,
    );

    // ContextBuilder's responsibility is to provide the *current* context.
    // If the conversation hasn't started (history is empty), we check if there's a pending question.
    // However, if the history is NOT empty, we trust it reflects the true state.
    const currentQuestion = this.context.config.getQuestion();
    if (currentQuestion && history.length === 0) {
      history.push({
        user: {
          text: currentQuestion,
        },
        model: {},
      });
    }

    return {
      environment: {
        cwd: process.cwd(),
        // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
        workspaces: this.context.config
          .getWorkspaceContext()
          .getDirectories() as string[],
      },
      history: {
        turns: history,
      },
    };
  }

  /**
   * Builds a minimal context with only the specified keys.
   */
  buildMinimalContext(
    requiredKeys: Array<keyof SafetyCheckInput['context']>,
  ): SafetyCheckInput['context'] {
    const fullContext = this.buildFullContext();
    const minimalContext: Partial<SafetyCheckInput['context']> = {};

    for (const key of requiredKeys) {
      if (key in fullContext) {
        // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-type-assertion
        (minimalContext as any)[key] = fullContext[key];
      }
    }

    // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
    return minimalContext as SafetyCheckInput['context'];
  }

  // Helper to convert Google GenAI Content[] to Safety Protocol ConversationTurn[]
  private convertHistoryToTurns(
    history: readonly Content[],
  ): ConversationTurn[] {
    const turns: ConversationTurn[] = [];
    let currentUserRequest: { text: string } | undefined;

    for (const content of history) {
      if (content.role === 'user') {
        if (currentUserRequest) {
          // Previous user turn didn't have a matching model response (or it was filtered out)
          // Push it as a turn with empty model response
          turns.push({ user: currentUserRequest, model: {} });
        }
        currentUserRequest = {
          text: content.parts?.map((p) => p.text).join('') || '',
        };
      } else if (content.role === 'model') {
        const modelResponse = {
          text:
            content.parts
              ?.filter((p) => p.text)
              .map((p) => p.text)
              .join('') || '',
          toolCalls:
            content.parts
              ?.filter((p) => 'functionCall' in p)
              // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
              .map((p) => p.functionCall as FunctionCall) || [],
        };

        if (currentUserRequest) {
          turns.push({ user: currentUserRequest, model: modelResponse });
          currentUserRequest = undefined;
        } else {
          // Model response without preceding user request.
          // This creates a turn with empty user text.
          turns.push({ user: { text: '' }, model: modelResponse });
        }
      }
    }

    if (currentUserRequest) {
      turns.push({ user: currentUserRequest, model: {} });
    }

    return turns;
  }
}
