import { captureCaught } from '@/lib/observability';

const NEUTRAL_GLOW = 'var(--color-deal-ambient-neutral)';
const SAMPLE_SIZE = 24;

const glowCache = new Map<string, Promise<string>>();

function clamp(value: number, min: number, max: number): number {
  return Math.min(max, Math.max(min, value));
}

function toDataUrlSvg(hex: string): string {
  return `data:image/svg+xml,${encodeURIComponent(
    `<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64"><rect fill="${hex}" width="100%" height="100%"/></svg>`,
  )}`;
}

function rgbToHsl(r: number, g: number, b: number): { h: number; s: number; l: number } {
  const red = r / 255;
  const green = g / 255;
  const blue = b / 255;
  const max = Math.max(red, green, blue);
  const min = Math.min(red, green, blue);
  const lightness = (max + min) / 2;
  const delta = max - min;
  if (delta === 0) {
    return { h: 0, s: 0, l: lightness };
  }
  const saturation = lightness > 0.5 ? delta / (2 - max - min) : delta / (max + min);
  let hue: number;
  switch (max) {
    case red:
      hue = (green - blue) / delta + (green < blue ? 6 : 0);
      break;
    case green:
      hue = (blue - red) / delta + 2;
      break;
    default:
      hue = (red - green) / delta + 4;
      break;
  }
  return { h: hue / 6, s: saturation, l: lightness };
}

function buildGlowColor(imageData: ImageData): string {
  let totalWeight = 0;
  let weightedHueX = 0;
  let weightedHueY = 0;
  let weightedSaturation = 0;
  let weightedLightness = 0;
  for (let index = 0; index < imageData.data.length; index += 4) {
    const alpha = imageData.data[index + 3] ?? 0;
    if (alpha < 32) continue;
    const red = imageData.data[index] ?? 0;
    const green = imageData.data[index + 1] ?? 0;
    const blue = imageData.data[index + 2] ?? 0;
    const { h, s, l } = rgbToHsl(red, green, blue);
    const weight = alpha / 255;
    totalWeight += weight;
    weightedHueX += Math.cos(h * Math.PI * 2) * weight;
    weightedHueY += Math.sin(h * Math.PI * 2) * weight;
    weightedSaturation += s * weight;
    weightedLightness += l * weight;
  }
  if (totalWeight === 0) return NEUTRAL_GLOW;
  const hue = (Math.atan2(weightedHueY, weightedHueX) / (Math.PI * 2) + 1) % 1;
  const saturation = clamp(weightedSaturation / totalWeight, 0.32, 0.82);
  const lightness = clamp(weightedLightness / totalWeight, 0.44, 0.68);
  const hueDegrees = Math.round(hue * 360) % 360;
  return `hsl(var(--deal-ambient-hue, ${hueDegrees}) var(--deal-ambient-saturation, ${Math.round(saturation * 100)}%) var(--deal-ambient-lightness, ${Math.round(lightness * 100)}%) / var(--deal-ambient-alpha, 0.28))`;
}

function loadImage(src: string): Promise<HTMLImageElement> {
  return new Promise((resolve, reject) => {
    const image = new window.Image();
    image.decoding = 'async';
    image.crossOrigin = 'anonymous';
    image.onload = () => resolve(image);
    image.onerror = () => reject(new Error(`Failed to load image: ${src}`));
    image.src = src;
  });
}

async function extractGlowColor(src: string): Promise<string> {
  try {
    const image = await loadImage(src);
    const canvas = document.createElement('canvas');
    canvas.width = SAMPLE_SIZE;
    canvas.height = SAMPLE_SIZE;
    const context = canvas.getContext('2d', { willReadFrequently: true });
    if (!context) return NEUTRAL_GLOW;
    context.drawImage(image, 0, 0, SAMPLE_SIZE, SAMPLE_SIZE);
    return buildGlowColor(context.getImageData(0, 0, SAMPLE_SIZE, SAMPLE_SIZE));
  } catch (err) {
    captureCaught(err, { scope: 'lib.deal-ambient.extractGlowColor', severity: 'warning' });
    return NEUTRAL_GLOW;
  }
}

export function getNeutralGlow(): string {
  return NEUTRAL_GLOW;
}

export function isHighContrastMode(): boolean {
  if (typeof document === 'undefined') return false;
  return document.documentElement.dataset.contrast === 'high';
}

export function getDealAmbientGlow(src: string | null | undefined): Promise<string> {
  if (!src) return Promise.resolve(NEUTRAL_GLOW);
  const cached = glowCache.get(src);
  if (cached) return cached;
  const pending = extractGlowColor(src).catch((err) => {
    captureCaught(err, { scope: 'lib.deal-ambient.getDealAmbientGlow', severity: 'warning' });
    return NEUTRAL_GLOW;
  });
  glowCache.set(src, pending);
  return pending;
}

export const SAMPLE_DEAL_AMBIENT_IMAGES = {
  warm: toDataUrlSvg('var(--color-deal-ambient-warm)'),
  cool: toDataUrlSvg('var(--color-deal-ambient-cool)'),
  fresh: toDataUrlSvg('var(--color-deal-ambient-fresh)'),
};
