import {
  classifyStandaloneRuntimeDecisionJsonKind,
  classifyControlPayloadPrefixRisk,
  containsControlPayloadFinal,
  containsControlPayloadPrefix,
  extractStandaloneRuntimeDecisionJsonBlocks,
  extractStandaloneRuntimeControlJsonBlocks,
  extractTextualToolCallName,
  hasPhaseOrPlanPayload,
  hasProviderInternalPayload,
  hasToolCallMarkup,
  looksLikeStandaloneProviderNativeToolCallJson,
  looksLikeStandaloneRuntimeControlJson,
  shouldHoldControlPayloadPrefix,
  shouldHoldTextualToolInvocationPrefix,
  type ControlPayloadClassifierOptions,
  type ControlPayloadPrefixRisk,
} from "../../shared/control-payload-classifier.js";
import type {
  TerminalOutputInvalidKind,
  TerminalOutputInvalidReasonCode,
} from "./runtime-observation.js";

export type TerminalOutputInvalidClassification = {
  invalidKind: TerminalOutputInvalidKind;
  reasonCode: TerminalOutputInvalidReasonCode;
  toolKnown?: boolean;
  toolName?: string;
};

export function containsTerminalControlPayload(
  text: string,
  toolNames: readonly string[] = [],
): boolean {
  return containsTerminalControlPayloadFinal(text, toolNames);
}

export function containsTerminalControlPayloadFinal(
  text: string,
  toolNames: readonly string[] = [],
  options: ControlPayloadClassifierOptions = {},
): boolean {
  return containsControlPayloadFinal(text, toolNames, options);
}

export function containsTerminalControlPayloadPrefix(
  text: string,
  toolNames: readonly string[] = [],
  options: ControlPayloadClassifierOptions = {},
): boolean {
  return containsControlPayloadPrefix(text, toolNames, options);
}

export function shouldHoldTerminalControlPayloadPrefix(text: string): boolean {
  return shouldHoldControlPayloadPrefix(text);
}

export function classifyTerminalControlPayloadPrefixRisk(
  text: string,
  toolNames: readonly string[] = [],
): ControlPayloadPrefixRisk {
  return classifyControlPayloadPrefixRisk(text, toolNames);
}

export function shouldHoldTerminalTextualToolInvocationPrefix(
  text: string,
  toolNames: readonly string[],
  options: { holdSingleCharacterPrefix?: boolean } = {},
): boolean {
  return shouldHoldTextualToolInvocationPrefix(text, toolNames, options);
}

export function classifyTerminalOutputInvalid(
  text: string,
  toolNames: readonly string[] = [],
): TerminalOutputInvalidClassification {
  const stripped = text.trim();
  if (!stripped) {
    return {
      invalidKind: "generic-control-payload",
      reasonCode: "structured-control-payload",
    };
  }
  const textualToolCall = extractTextualToolCallName(stripped, toolNames);
  const runtimeDecisionBlocks = extractStandaloneRuntimeDecisionJsonBlocks(stripped);
  const runtimeDecisionKind = runtimeDecisionBlocks
    .map(classifyStandaloneRuntimeDecisionJsonKind)
    .find((kind) => kind !== undefined);
  if (runtimeDecisionKind) {
    const runtimeToolName =
      runtimeDecisionKind === "tool"
        ? runtimeDecisionBlocks.map(extractRuntimeDecisionToolName).find(Boolean)
        : undefined;
    return {
      invalidKind:
        runtimeDecisionKind === "tool"
          ? "textual-tool-call"
          : runtimeDecisionKind === "phase_result" || runtimeDecisionKind === "plan_update"
            ? "phase-or-plan-payload"
            : "generic-control-payload",
      reasonCode: "runtime-decision-json",
      ...(runtimeToolName
        ? { toolKnown: toolNames.includes(runtimeToolName), toolName: runtimeToolName }
        : {}),
    };
  }
  const runtimeControlBlocks = extractStandaloneRuntimeControlJsonBlocks(stripped);
  if (
    looksLikeStandaloneProviderNativeToolCallJson(stripped) ||
    runtimeControlBlocks.some(looksLikeStandaloneProviderNativeToolCallJson)
  ) {
    return {
      invalidKind: "textual-tool-call",
      reasonCode: "provider-native-tool-call-json",
    };
  }
  if (textualToolCall) {
    return {
      invalidKind: "textual-tool-call",
      reasonCode: "textual-tool-call",
      toolKnown: textualToolCall.known,
      toolName: textualToolCall.toolName,
    };
  }
  if (looksLikeStandaloneRuntimeControlJson(stripped) || runtimeControlBlocks.length > 0) {
    return {
      invalidKind: "textual-tool-call",
      reasonCode: "structured-control-payload",
    };
  }
  if (hasToolCallMarkup(stripped)) {
    return { invalidKind: "generic-control-payload", reasonCode: "tool-call-marker" };
  }
  if (hasProviderInternalPayload(stripped)) {
    return {
      invalidKind: "provider-internal-payload",
      reasonCode: "provider-internal-payload",
    };
  }
  if (hasPhaseOrPlanPayload(stripped)) {
    return {
      invalidKind: "phase-or-plan-payload",
      reasonCode: "structured-control-payload",
    };
  }
  return { invalidKind: "generic-control-payload", reasonCode: "structured-control-payload" };
}

function extractRuntimeDecisionToolName(text: string): string | undefined {
  const normalized = text.trim();
  if (normalized.length > 8_192) {
    return normalized.match(/"(?:toolName|providerToolName)"\s*:\s*"([^"]+)"/i)?.[1];
  }
  try {
    return extractRuntimeDecisionToolNameValue(JSON.parse(normalized));
  } catch {
    return undefined;
  }
}

function extractRuntimeDecisionToolNameValue(value: unknown): string | undefined {
  if (Array.isArray(value)) {
    return value.map(extractRuntimeDecisionToolNameValue).find(Boolean);
  }
  if (!value || typeof value !== "object") {
    return undefined;
  }
  const record = value as Record<string, unknown>;
  if (record.kind === "tool") {
    if (typeof record.toolName === "string") {
      return record.toolName;
    }
    if (typeof record.providerToolName === "string") {
      return record.providerToolName;
    }
  }
  return undefined;
}
