import type {
  PostAnalytics,
  Alert,
  RankableMetric,
} from "../models/types.js";
import { ALERT_THRESHOLDS } from "../models/types.js";
import {
  mean,
  deviationsFromMean,
  percentChange,
} from "./stats.js";

/**
 * Analyze posts for spikes and drops based on standard deviation thresholds.
 * For each post, checks if its metric value deviates significantly from the mean.
 * Returns array of alerts sorted by severity (critical first).
 */
export function detectAlerts(
  posts: PostAnalytics[],
  metricKey: RankableMetric = "impressions"
): Alert[] {
  if (posts.length === 0) return [];

  const alerts: Alert[] = [];

  // Extract metric values
  const values = posts.map((post) => post.metrics[metricKey]);
  const avg = mean(values);

  // Check each post for significant deviations
  for (const post of posts) {
    const value = post.metrics[metricKey];
    const deviations = deviationsFromMean(value, values);

    // Spike detection
    if (deviations > ALERT_THRESHOLDS.spike) {
      alerts.push({
        type: "spike",
        severity: "info",
        metric: metricKey,
        message: `Post "${post.title}" has unusually high ${metricKey}: ${value.toLocaleString()} (${deviations.toFixed(1)} std deviations above mean)`,
        postId: post.id,
        value,
        baseline: avg,
        deviations,
      });
    }

    // Drop detection
    if (deviations < ALERT_THRESHOLDS.drop) {
      alerts.push({
        type: "drop",
        severity: "warning",
        metric: metricKey,
        message: `Post "${post.title}" has unusually low ${metricKey}: ${value.toLocaleString()} (${Math.abs(deviations).toFixed(1)} std deviations below mean)`,
        postId: post.id,
        value,
        baseline: avg,
        deviations,
      });
    }
  }

  // Sort by severity: critical > warning > info
  const severityOrder = { critical: 0, warning: 1, info: 2 };
  alerts.sort((a, b) => severityOrder[a.severity] - severityOrder[b.severity]);

  return alerts;
}

/**
 * Compare week-over-week metrics and generate alerts for significant changes.
 * Uses percentChange and ALERT_THRESHOLDS for weekly drops and spikes.
 */
export function detectWeeklyAlerts(
  currentWeekMetrics: { impressions: number; engagementRate: number },
  previousWeekMetrics: { impressions: number; engagementRate: number }
): Alert[] {
  const alerts: Alert[] = [];

  // Analyze impressions
  const impressionChange = percentChange(
    currentWeekMetrics.impressions,
    previousWeekMetrics.impressions
  );

  if (impressionChange < ALERT_THRESHOLDS.weeklyDropCritical) {
    alerts.push({
      type: "drop",
      severity: "critical",
      metric: "impressions",
      message: `Critical drop in weekly impressions: ${impressionChange.toFixed(1)}% (from ${previousWeekMetrics.impressions.toLocaleString()} to ${currentWeekMetrics.impressions.toLocaleString()})`,
      value: currentWeekMetrics.impressions,
      baseline: previousWeekMetrics.impressions,
      deviations: impressionChange / 10, // Rough conversion to deviations
    });
  } else if (impressionChange < ALERT_THRESHOLDS.weeklyDropWarning) {
    alerts.push({
      type: "drop",
      severity: "warning",
      metric: "impressions",
      message: `Weekly impressions dropped by ${Math.abs(impressionChange).toFixed(1)}%: from ${previousWeekMetrics.impressions.toLocaleString()} to ${currentWeekMetrics.impressions.toLocaleString()}`,
      value: currentWeekMetrics.impressions,
      baseline: previousWeekMetrics.impressions,
      deviations: impressionChange / 10,
    });
  } else if (impressionChange > ALERT_THRESHOLDS.weeklySpikeInfo) {
    alerts.push({
      type: "spike",
      severity: "info",
      metric: "impressions",
      message: `Strong growth in weekly impressions: +${impressionChange.toFixed(1)}% (from ${previousWeekMetrics.impressions.toLocaleString()} to ${currentWeekMetrics.impressions.toLocaleString()})`,
      value: currentWeekMetrics.impressions,
      baseline: previousWeekMetrics.impressions,
      deviations: impressionChange / 10,
    });
  }

  // Analyze engagement rate
  const engagementChange = percentChange(
    currentWeekMetrics.engagementRate,
    previousWeekMetrics.engagementRate
  );

  if (engagementChange < ALERT_THRESHOLDS.weeklyDropCritical) {
    alerts.push({
      type: "drop",
      severity: "critical",
      metric: "engagementRate",
      message: `Critical drop in weekly engagement rate: ${engagementChange.toFixed(1)}% (from ${previousWeekMetrics.engagementRate.toFixed(2)}% to ${currentWeekMetrics.engagementRate.toFixed(2)}%)`,
      value: currentWeekMetrics.engagementRate,
      baseline: previousWeekMetrics.engagementRate,
      deviations: engagementChange / 10,
    });
  } else if (engagementChange < ALERT_THRESHOLDS.weeklyDropWarning) {
    alerts.push({
      type: "drop",
      severity: "warning",
      metric: "engagementRate",
      message: `Weekly engagement rate dropped by ${Math.abs(engagementChange).toFixed(1)}%: from ${previousWeekMetrics.engagementRate.toFixed(2)}% to ${currentWeekMetrics.engagementRate.toFixed(2)}%`,
      value: currentWeekMetrics.engagementRate,
      baseline: previousWeekMetrics.engagementRate,
      deviations: engagementChange / 10,
    });
  } else if (engagementChange > ALERT_THRESHOLDS.weeklySpikeInfo) {
    alerts.push({
      type: "spike",
      severity: "info",
      metric: "engagementRate",
      message: `Strong growth in weekly engagement rate: +${engagementChange.toFixed(1)}% (from ${previousWeekMetrics.engagementRate.toFixed(2)}% to ${currentWeekMetrics.engagementRate.toFixed(2)}%)`,
      value: currentWeekMetrics.engagementRate,
      baseline: previousWeekMetrics.engagementRate,
      deviations: engagementChange / 10,
    });
  }

  // Sort by severity: critical > warning > info
  const severityOrder = { critical: 0, warning: 1, info: 2 };
  alerts.sort((a, b) => severityOrder[a.severity] - severityOrder[b.severity]);

  return alerts;
}
