import type { PsiResponse } from "./psi-api";
import type { CoreWebVital, WebVitalGrade } from "./types";

interface VitalThresholds {
  good: number;
  poor: number;
  unit: "ms" | "s" | "score";
  displayName: string;
  description: string;
}

const VITAL_CONFIG: Record<"LCP" | "INP" | "CLS" | "FCP" | "TTFB", VitalThresholds> = {
  LCP: {
    good: 2500,
    poor: 4000,
    unit: "ms",
    displayName: "Largest Contentful Paint",
    description: "Time until the largest visible content element is rendered",
  },
  INP: {
    good: 200,
    poor: 500,
    unit: "ms",
    displayName: "Interaction to Next Paint",
    description: "Responsiveness delay from user input to next visual update",
  },
  CLS: {
    good: 0.1,
    poor: 0.25,
    unit: "score",
    displayName: "Cumulative Layout Shift",
    description: "Visual stability -- unexpected layout shifts during page load",
  },
  FCP: {
    good: 1800,
    poor: 3000,
    unit: "ms",
    displayName: "First Contentful Paint",
    description: "Time until the first content element is rendered",
  },
  TTFB: {
    good: 800,
    poor: 1800,
    unit: "ms",
    displayName: "Time to First Byte",
    description: "Server response time before content begins downloading",
  },
};

function gradeValue(value: number, good: number, poor: number): WebVitalGrade {
  if (value <= good) return "good";
  if (value <= poor) return "needs_improvement";
  return "poor";
}

function categoryToGrade(category: string): WebVitalGrade {
  const c = category.toUpperCase();
  if (c === "FAST" || c === "GOOD") return "good";
  if (c === "AVERAGE" || c === "NEEDS_IMPROVEMENT") return "needs_improvement";
  return "poor";
}

export function extractCoreWebVitals(psiResponse: PsiResponse): CoreWebVital[] {
  const lh = psiResponse.lighthouseResult;
  const field = psiResponse.loadingExperience?.metrics ?? {};

  const vitals: CoreWebVital[] = [];

  // LCP
  const lcpConfig = VITAL_CONFIG.LCP;
  const lcpLab = lh.audits["largest-contentful-paint"]?.numericValue ?? null;
  const lcpField = field.LARGEST_CONTENTFUL_PAINT_MS?.percentile ?? null;
  vitals.push({
    metric: "LCP",
    ...lcpConfig,
    labValue: lcpLab,
    labGrade: lcpLab != null ? gradeValue(lcpLab, lcpConfig.good, lcpConfig.poor) : null,
    fieldValue: lcpField,
    fieldGrade: field.LARGEST_CONTENTFUL_PAINT_MS
      ? categoryToGrade(field.LARGEST_CONTENTFUL_PAINT_MS.category)
      : null,
    goodThreshold: lcpConfig.good,
    poorThreshold: lcpConfig.poor,
  });

  // INP
  const inpConfig = VITAL_CONFIG.INP;
  const inpLab = lh.audits["interaction-to-next-paint"]?.numericValue ?? null;
  const inpField = field.INTERACTION_TO_NEXT_PAINT?.percentile ?? null;
  vitals.push({
    metric: "INP",
    ...inpConfig,
    labValue: inpLab,
    labGrade: inpLab != null ? gradeValue(inpLab, inpConfig.good, inpConfig.poor) : null,
    fieldValue: inpField,
    fieldGrade: field.INTERACTION_TO_NEXT_PAINT
      ? categoryToGrade(field.INTERACTION_TO_NEXT_PAINT.category)
      : null,
    goodThreshold: inpConfig.good,
    poorThreshold: inpConfig.poor,
  });

  // CLS
  const clsConfig = VITAL_CONFIG.CLS;
  const clsLab = lh.audits["cumulative-layout-shift"]?.numericValue ?? null;
  const clsField = field.CUMULATIVE_LAYOUT_SHIFT_SCORE?.percentile
    ? field.CUMULATIVE_LAYOUT_SHIFT_SCORE.percentile / 100
    : null;
  vitals.push({
    metric: "CLS",
    ...clsConfig,
    labValue: clsLab,
    labGrade: clsLab != null ? gradeValue(clsLab, clsConfig.good, clsConfig.poor) : null,
    fieldValue: clsField,
    fieldGrade: field.CUMULATIVE_LAYOUT_SHIFT_SCORE
      ? categoryToGrade(field.CUMULATIVE_LAYOUT_SHIFT_SCORE.category)
      : null,
    goodThreshold: clsConfig.good,
    poorThreshold: clsConfig.poor,
  });

  // FCP
  const fcpConfig = VITAL_CONFIG.FCP;
  const fcpLab = lh.audits["first-contentful-paint"]?.numericValue ?? null;
  const fcpField = field.FIRST_CONTENTFUL_PAINT_MS?.percentile ?? null;
  vitals.push({
    metric: "FCP",
    ...fcpConfig,
    labValue: fcpLab,
    labGrade: fcpLab != null ? gradeValue(fcpLab, fcpConfig.good, fcpConfig.poor) : null,
    fieldValue: fcpField,
    fieldGrade: field.FIRST_CONTENTFUL_PAINT_MS
      ? categoryToGrade(field.FIRST_CONTENTFUL_PAINT_MS.category)
      : null,
    goodThreshold: fcpConfig.good,
    poorThreshold: fcpConfig.poor,
  });

  // TTFB
  const ttfbConfig = VITAL_CONFIG.TTFB;
  const ttfbLab = lh.audits["server-response-time"]?.numericValue ?? null;
  const ttfbField = field.EXPERIMENTAL_TIME_TO_FIRST_BYTE?.percentile ?? null;
  vitals.push({
    metric: "TTFB",
    ...ttfbConfig,
    labValue: ttfbLab,
    labGrade: ttfbLab != null ? gradeValue(ttfbLab, ttfbConfig.good, ttfbConfig.poor) : null,
    fieldValue: ttfbField,
    fieldGrade: field.EXPERIMENTAL_TIME_TO_FIRST_BYTE
      ? categoryToGrade(field.EXPERIMENTAL_TIME_TO_FIRST_BYTE.category)
      : null,
    goodThreshold: ttfbConfig.good,
    poorThreshold: ttfbConfig.poor,
  });

  return vitals;
}
