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

import type {
  MCPServerStatus,
  ToolConfirmationOutcome,
} from '@google/gemini-cli-core';
import type { TaskState } from '@a2a-js/sdk';

// Interfaces and enums for the CoderAgent protocol.

export enum CoderAgentEvent {
  /**
   * An event requesting one or more tool call confirmations.
   */
  ToolCallConfirmationEvent = 'tool-call-confirmation',
  /**
   * An event updating on the status of one or more tool calls.
   */
  ToolCallUpdateEvent = 'tool-call-update',
  /**
   * An event providing text updates on the task.
   */
  TextContentEvent = 'text-content',
  /**
   * An event that indicates a change in the task's execution state.
   */
  StateChangeEvent = 'state-change',
  /**
   * An user-sent event to initiate the agent.
   */
  StateAgentSettingsEvent = 'agent-settings',
  /**
   * An event that contains a thought from the agent.
   */
  ThoughtEvent = 'thought',
  /**
   * An event that contains citation from the agent.
   */
  CitationEvent = 'citation',
}

export interface AgentSettings {
  kind: CoderAgentEvent.StateAgentSettingsEvent;
  workspacePath: string;
  autoExecute?: boolean;
}

export interface ToolCallConfirmation {
  kind: CoderAgentEvent.ToolCallConfirmationEvent;
}

export interface ToolCallUpdate {
  kind: CoderAgentEvent.ToolCallUpdateEvent;
}

export interface TextContent {
  kind: CoderAgentEvent.TextContentEvent;
}

export interface StateChange {
  kind: CoderAgentEvent.StateChangeEvent;
}

export interface Thought {
  kind: CoderAgentEvent.ThoughtEvent;
}

export interface Citation {
  kind: CoderAgentEvent.CitationEvent;
}

export type ThoughtSummary = {
  subject: string;
  description: string;
};

export interface ToolConfirmationResponse {
  outcome: ToolConfirmationOutcome;
  callId: string;
}

export type CoderAgentMessage =
  | AgentSettings
  | ToolCallConfirmation
  | ToolCallUpdate
  | TextContent
  | StateChange
  | Thought
  | Citation;

export interface TaskMetadata {
  id: string;
  contextId: string;
  taskState: TaskState;
  model: string;
  mcpServers: Array<{
    name: string;
    status: MCPServerStatus;
    tools: Array<{
      name: string;
      description: string;
      parameterSchema: unknown;
    }>;
  }>;
  availableTools: Array<{
    name: string;
    description: string;
    parameterSchema: unknown;
  }>;
}

export interface PersistedStateMetadata {
  _agentSettings: AgentSettings;
  _taskState: TaskState;
}

export type PersistedTaskMetadata = { [k: string]: unknown };

export const METADATA_KEY = '__persistedState';

function isAgentSettings(value: unknown): value is AgentSettings {
  return (
    typeof value === 'object' &&
    value !== null &&
    'kind' in value &&
    value.kind === CoderAgentEvent.StateAgentSettingsEvent &&
    'workspacePath' in value &&
    typeof value.workspacePath === 'string'
  );
}

function isPersistedStateMetadata(
  value: unknown,
): value is PersistedStateMetadata {
  return (
    typeof value === 'object' &&
    value !== null &&
    '_agentSettings' in value &&
    '_taskState' in value &&
    isAgentSettings(value._agentSettings)
  );
}

export function getPersistedState(
  metadata: PersistedTaskMetadata,
): PersistedStateMetadata | undefined {
  const state = metadata?.[METADATA_KEY];
  if (isPersistedStateMetadata(state)) {
    return state;
  }
  return undefined;
}

export function getContextIdFromMetadata(
  metadata: PersistedTaskMetadata | undefined,
): string | undefined {
  if (!metadata) {
    return undefined;
  }
  const contextId = metadata['_contextId'];
  return typeof contextId === 'string' ? contextId : undefined;
}

export function getAgentSettingsFromMetadata(
  metadata: PersistedTaskMetadata | undefined,
): AgentSettings | undefined {
  if (!metadata) {
    return undefined;
  }
  const coderAgent = metadata['coderAgent'];
  if (isAgentSettings(coderAgent)) {
    return coderAgent;
  }
  return undefined;
}

export function setPersistedState(
  metadata: PersistedTaskMetadata,
  state: PersistedStateMetadata,
): PersistedTaskMetadata {
  return {
    ...metadata,
    [METADATA_KEY]: state,
  };
}
