// ─── Process Observer — Conversation Analyzer ───────────────────────────────
// Deterministic signal detection rules for conversation quality analysis.
// No LLM calls — pure string matching on message content.

import { observerFindings } from "@/lib/metrics";

export interface ConversationMessage {
  id: string;
  role: "user" | "assistant" | "system";
  content: string;
  agentId: string;
  routeContext: string;
}

export type FindingType =
  | "tool_failure"
  | "config_gap"
  | "agent_quality"
  | "user_friction"
  | "endpoint_underperformance"   // generated by orchestrator-evaluator on regression
  | "instruction_regression";      // generated by orchestrator-evaluator on regression

export type Severity = "critical" | "high" | "medium" | "low";

export interface ObservationFinding {
  type: FindingType;
  severity: Severity;
  title: string;
  description: string;
  rootCause: string | null;
  sentiment: "positive" | "neutral" | "negative";
  sourceMessageIds: string[];
  suggestedAction: string;
}

// ─── Detection Rules ────────────────────────────────────────────────────────

const TOOL_FAILURE_PATTERNS: RegExp[] = [
  /\btool\s+\S+\s+failed\b/i,
  /\bfailed:\s/i,
  /\bquota\b.*\bdisabled\b/i,
];

const CONFIG_GAP_PATTERNS: RegExp[] = [
  /\bnot configured\b/i,
  /\bunavailable\b.*\bpre-configured\b/i,
];

const REASONING_PHRASES: RegExp[] = [
  /\bwe need to\b/i,
  /\bthe instruction says\b/i,
  /\bbut we can('t| not| still)\b/i,
  /\bwe assume\b/i,
  /\bwe should\b/i,
  /\blet me think\b/i,
  /\bthe user('s| is)\b/i,
];

const WHATS_NEXT_PATTERNS: RegExp[] = [
  /\bwhat('s| is| do i do)\s+next\b/i,
  /\bwhat\s+do\s+i\s+do\s+next\b/i,
];

const MIN_REASONING_LENGTH = 100;
const MIN_REASONING_MATCHES = 2;

// ─── Detector Functions ─────────────────────────────────────────────────────

function detectToolFailures(messages: ConversationMessage[]): ObservationFinding[] {
  const findings: ObservationFinding[] = [];
  for (const m of messages) {
    if (m.role !== "system") continue;
    for (const pattern of TOOL_FAILURE_PATTERNS) {
      if (pattern.test(m.content)) {
        findings.push({
          type: "tool_failure",
          severity: "high",
          title: "MCP tool execution failed",
          description: m.content.slice(0, 200),
          rootCause: null,
          sentiment: "neutral",
          sourceMessageIds: [m.id],
          suggestedAction: "Investigate the tool failure and fix the underlying issue",
        });
        break; // one finding per message
      }
    }
  }
  return findings;
}

function detectConfigGaps(messages: ConversationMessage[]): ObservationFinding[] {
  const findings: ObservationFinding[] = [];
  for (const m of messages) {
    if (m.role !== "system") continue;
    for (const pattern of CONFIG_GAP_PATTERNS) {
      if (pattern.test(m.content)) {
        findings.push({
          type: "config_gap",
          severity: "medium",
          title: "Configuration gap detected",
          description: m.content.slice(0, 200),
          rootCause: null,
          sentiment: "neutral",
          sourceMessageIds: [m.id],
          suggestedAction: "An administrator should configure the missing service",
        });
        break;
      }
    }
  }
  return findings;
}

function detectAgentQuality(messages: ConversationMessage[]): ObservationFinding[] {
  const findings: ObservationFinding[] = [];
  for (const m of messages) {
    if (m.role !== "assistant") continue;
    if (m.content.length < MIN_REASONING_LENGTH) continue;

    let matchCount = 0;
    for (const pattern of REASONING_PHRASES) {
      if (pattern.test(m.content)) matchCount++;
    }
    if (matchCount >= MIN_REASONING_MATCHES) {
      findings.push({
        type: "agent_quality",
        severity: "medium",
        title: "Agent reasoning leak in response",
        description: "Assistant response contains internal reasoning patterns visible to the user",
        rootCause: null,
        sentiment: "negative",
        sourceMessageIds: [m.id],
        suggestedAction: "Review agent prompt to suppress internal reasoning from user-facing output",
      });
    }
  }
  return findings;
}

function detectUserFriction(messages: ConversationMessage[]): ObservationFinding[] {
  const findings: ObservationFinding[] = [];

  // Detect "what's next?" patterns
  for (const m of messages) {
    if (m.role !== "user") continue;
    for (const pattern of WHATS_NEXT_PATTERNS) {
      if (pattern.test(m.content)) {
        findings.push({
          type: "user_friction",
          severity: "low",
          title: "User asked what to do next",
          description: "User appears uncertain about the next step",
          rootCause: null,
          sentiment: "neutral",
          sourceMessageIds: [m.id],
          suggestedAction: "Improve proactive guidance in agent responses",
        });
        break;
      }
    }
  }

  // Detect repeated user messages
  const userMessages = messages.filter((m) => m.role === "user");
  for (let i = 1; i < userMessages.length; i++) {
    const current = userMessages[i]!;
    for (let j = 0; j < i; j++) {
      const previous = userMessages[j]!;
      if (
        current.content === previous.content ||
        current.content.includes(previous.content) ||
        previous.content.includes(current.content)
      ) {
        // Avoid duplicate findings for same message pair
        const alreadyFound = findings.some(
          (f) =>
            f.type === "user_friction" &&
            f.title === "User repeated themselves" &&
            f.sourceMessageIds.includes(current.id),
        );
        if (!alreadyFound) {
          findings.push({
            type: "user_friction",
            severity: "medium",
            title: "User repeated themselves",
            description: `User sent a similar message more than once: "${current.content.slice(0, 80)}"`,
            rootCause: null,
            sentiment: "negative",
            sourceMessageIds: [previous.id, current.id],
            suggestedAction: "Investigate why the agent did not address the user's request",
          });
        }
        break;
      }
    }
  }

  return findings;
}

// ─── Human Feedback Inference ────────────────────────────────────────────────

/** Infer human satisfaction score from conversation pair (AI response + human follow-up) */
export function inferHumanScore(
  aiMessage: ConversationMessage,
  humanFollowUp: ConversationMessage,
): number | null {
  const content = humanFollowUp.content.toLowerCase();

  // Positive signals → score 4
  if (/\b(thanks|thank you|great|perfect|exactly|awesome|helpful)\b/.test(content)) {
    return 4;
  }

  // Negative signals → score 1
  if (/\b(wrong|incorrect|no[,.]?\s*(that'?s|it'?s) not|you (missed|forgot|didn'?t))\b/.test(content)) {
    return 1;
  }

  // Rephrasing detection → score 2
  if (humanFollowUp.role === "user" && content.length > 20) {
    if (/\b(again|already asked|i said|i meant)\b/.test(content)) {
      return 2;
    }
  }

  // Neutral — no clear signal
  return null;
}

// ─── Main Analyzer ──────────────────────────────────────────────────────────

export function analyzeConversation(messages: ConversationMessage[]): ObservationFinding[] {
  const findings = [
    ...detectToolFailures(messages),
    ...detectConfigGaps(messages),
    ...detectAgentQuality(messages),
    ...detectUserFriction(messages),
  ];

  // Record metrics for Prometheus
  for (const f of findings) {
    observerFindings.inc({ type: f.type, severity: f.severity });
  }

  return findings;
}
