export interface PostAnalytics {
  id: string; // Hash of title + date
  title: string; // First ~100 chars of post content
  publishedDate: string; // YYYY-MM-DD
  metrics: PostMetrics;
  importedAt: string; // ISO datetime
  exportSource: string; // Original CSV filename
}

export interface PostMetrics {
  impressions: number;
  reactions: number;
  comments: number;
  shares: number;
  clicks: number;
  engagementRate: number; // (reactions+comments+shares+clicks)/impressions * 100
  // `saves` is OPTIONAL and manually entered. LinkedIn's CSV export does NOT
  // include it and there is no self-serve API to pull it — but the count IS
  // visible in the native post analytics UI (~Sept 2025 onward). The ingest
  // path is the user adding a `Saves` column to the CSV they read off it; the
  // parser picks it up when present (see csv-parser.ts). When the column or a
  // cell is absent, `saves` stays undefined — "unknown", never coerced to 0.
  // It is deliberately NOT folded into engagementRate (which stays comparable
  // to historical, saves-free data) — saves is surfaced as its own signal.
  saves?: number;
  // NOTE: `dwell` remains absent and unmeasurable. Dwell time is internal to
  // LinkedIn for organic posts — not exportable, no UI count to transcribe, no
  // API. Do not fabricate a dwell field or surface.
}

export interface AnalyticsBatch {
  batchId: string; // UUID-like identifier
  importedAt: string; // ISO datetime
  exportFilename: string;
  dateRange: { from: string; to: string };
  postCount: number;
  posts: PostAnalytics[];
}

export interface WeeklyReport {
  week: string; // ISO week e.g. "2026-W05"
  generatedAt: string;
  summary: {
    totalPosts: number;
    totalImpressions: number;
    totalReactions: number;
    totalComments: number;
    totalShares: number;
    totalClicks: number;
    totalSaves?: number; // optional — present only when ≥1 post carries manual saves data
    avgEngagementRate: number;
    avgImpressionsPerPost: number;
  };
  topPerformers: PostAnalytics[];
  underperformers: PostAnalytics[];
  trends: {
    impressionsTrend: TrendDirection;
    engagementTrend: TrendDirection;
    comparedTo: string;
    percentChange: {
      impressions: number;
      engagement: number;
    };
  };
  alerts: Alert[];
}

export type TrendDirection = "up" | "down" | "stable";

/**
 * Metric keys that are always present and numeric — safe for trend/alert ranking
 * and `metrics[key]` index access. Excludes the optional, manually-entered
 * `saves`, which is sparse and would type as `number | undefined` under index
 * access (and is not a rankable trend metric). This is the runtime whitelist the
 * CLI and alert engine have always used.
 */
export type RankableMetric =
  | "impressions"
  | "reactions"
  | "comments"
  | "shares"
  | "clicks"
  | "engagementRate";

export interface Alert {
  type: "spike" | "drop" | "milestone";
  severity: "info" | "warning" | "critical";
  metric: string;
  message: string;
  postId?: string;
  value: number;
  baseline: number;
  deviations: number;
}

export interface DayOfWeekMetrics {
  dayName: string; // "Monday" through "Sunday"
  dayIndex: number; // 1=Monday, 7=Sunday (ISO weekday)
  postCount: number;
  avgImpressions: number;
  avgEngagementRate: number;
  bestPost?: PostAnalytics;
}

export interface HeatmapReport {
  generatedAt: string;
  postsAnalyzed: number;
  dateRange: { from: string; to: string };
  byDayOfWeek: DayOfWeekMetrics[]; // 7 entries, Mon-Sun ordered
  bestDayImpressions: string;
  bestDayEngagement: string;
}

export interface MonthlyReport {
  month: string; // "YYYY-MM"
  generatedAt: string;
  summary: {
    totalPosts: number;
    totalImpressions: number;
    totalReactions: number;
    totalComments: number;
    totalShares: number;
    totalClicks: number;
    totalSaves?: number; // optional — present only when ≥1 post carries manual saves data
    avgEngagementRate: number;
    avgImpressionsPerPost: number;
  };
  topPerformers: PostAnalytics[];
  byWeek: {
    week: string;
    postCount: number;
    avgImpressions: number;
    avgEngagementRate: number;
  }[];
  trends: {
    comparedTo: string | null;
    percentChange: {
      impressions: number | null;
      engagement: number | null;
      postCount: number | null;
    };
  };
  alerts: Alert[];
}

export const ALERT_THRESHOLDS = {
  spike: 2.0,
  drop: -1.5,
  weeklyDropWarning: -30,
  weeklyDropCritical: -50,
  weeklySpikeInfo: 100,
} as const;
