/**
 * TelemetryAnalystAgent — queries telemetry clusters for the incident time
 * window and produces structured TelemetryFindings with hypotheses and
 * recommended next actions.
 */

import { randomUUID } from 'node:crypto';
import { telemetryClusters, type TelemetryCluster } from '../../../lib/platform-client.js';
import type { DispatchDecision, TelemetryFindings, ClusterRef } from '../types.js';

export async function analyze(
  decision: DispatchDecision,
  opts: { token?: string }
): Promise<TelemetryFindings> {
  const { runContext, brief, resolvedTimeWindow } = decision;
  const stepId = `step_telemetry_${randomUUID().slice(0, 8)}`;
  const ctx = { ...runContext, stepId };

  let clusters: ClusterRef[] = [];
  let queryError: string | undefined;

  try {
    const result = await telemetryClusters(
      { from: resolvedTimeWindow.from, to: resolvedTimeWindow.to },
      { token: opts.token, requestId: runContext.requestId, productId: brief.productId }
    );

    clusters = result.clusters
      .filter((c: TelemetryCluster) => c.status !== 'resolved' && c.status !== 'ignored')
      .map(
        (c: TelemetryCluster): ClusterRef => ({
          clusterId: c.id,
          pk: c.pk,
          fingerprint: c.fingerprint,
          severity: c.severity,
          totalCount: c.totalCount,
          lastSeenAt: c.lastSeenAt,
          platform: c.platform,
          module: c.module,
          sampleMessage: c.sampleMessage,
        })
      );

    // Filter by platform if the incident report names one
    if (brief.userReport.platform) {
      const p = brief.userReport.platform.toLowerCase();
      const platformClusters = clusters.filter(c => c.platform.toLowerCase() === p);
      if (platformClusters.length > 0) clusters = platformClusters;
    }

    // Sort by totalCount descending
    clusters.sort((a, b) => b.totalCount - a.totalCount);
  } catch (err) {
    queryError = err instanceof Error ? err.message : String(err);
  }

  const topHypotheses = deriveHypotheses(clusters, brief.userReport.summary);
  const recommendedActions = deriveActions(clusters, decision);

  return { runContext: ctx, clusters, topHypotheses, recommendedActions, queryError };
}

// ── Heuristic hypothesis generator ────────────────────────────────────────

function deriveHypotheses(clusters: ClusterRef[], summary: string): string[] {
  const hypotheses: string[] = [];
  const lower = summary.toLowerCase();

  if (clusters.length === 0) {
    hypotheses.push('No open error clusters found — issue may be intermittent or not yet surfaced');
    return hypotheses;
  }

  const fatalClusters = clusters.filter(c => c.severity === 'fatal');
  if (fatalClusters.length > 0) {
    hypotheses.push(
      `${fatalClusters.length} fatal cluster(s) detected — highest priority for investigation`
    );
  }

  const topCluster = clusters[0];
  if (topCluster.sampleMessage) {
    hypotheses.push(`Top cluster message: "${topCluster.sampleMessage}"`);
  }

  if (lower.includes('dictation') || lower.includes('speech') || lower.includes('transcri')) {
    hypotheses.push('Audio permission or microphone access may be revoked');
    hypotheses.push('Speech-to-text pipeline may have a timeout or encoding error');
  }

  if (lower.includes('insert') || lower.includes('paste') || lower.includes('nothing')) {
    hypotheses.push('Text insertion API returned a no-op — possible permission or focus issue');
  }

  if (lower.includes('crash') || lower.includes('fatal')) {
    hypotheses.push('Memory pressure or unexpected nil dereference in affected module');
  }

  const modules = [
    ...new Set(
      clusters
        .slice(0, 5)
        .map(c => c.module)
        .filter(Boolean)
    ),
  ];
  if (modules.length > 0) {
    hypotheses.push(`Affected modules: ${modules.join(', ')}`);
  }

  return hypotheses.slice(0, 5);
}

function deriveActions(clusters: ClusterRef[], decision: DispatchDecision): string[] {
  const actions: string[] = [];

  if (clusters.length === 0) {
    actions.push('Widen time window or check alternate platforms');
    actions.push('Verify telemetry is enabled and events are being ingested');
    return actions;
  }

  const hasTarget = !!(
    decision.brief.userReport.userId || decision.brief.userReport.anonymousInstallId
  );

  if (hasTarget && !decision.brief.openDiagnosticsSession) {
    actions.push(
      'Re-run with openDiagnosticsSession: true to capture a live trace for the affected user'
    );
  }

  const fatalClusters = clusters.filter(c => c.severity === 'fatal');
  if (fatalClusters.length > 0) {
    actions.push(
      `Resolve or investigate ${fatalClusters.length} fatal cluster(s): ` +
        fatalClusters
          .slice(0, 3)
          .map(c => c.clusterId)
          .join(', ')
    );
  }

  if (clusters.length >= 3) {
    actions.push(
      'Consider creating a targeted telemetry policy to capture debug-level events for affected module'
    );
  }

  actions.push(`Review top cluster (${clusters[0].clusterId}) in admin telemetry explorer`);

  return actions.slice(0, 5);
}
