// @design-system: primitives/Image
// Registered at /design-system#image-primitive - Phase 3 (Agent 3E) will render the gallery.

import type React from 'react';
import { cn } from '@/lib/cn';
import { captureCaught } from '@/lib/observability';
import {
  buildSrcSet,
  buildVariantUrl,
  DEFAULT_IMAGE_SIZES,
  type ImageVariant,
} from './buildVariantUrl';
import { VARIANT_MATRIX } from '@/lib/imageVariants';

/**
 * Per-variant default `sizes` attribute. Browsers without a `sizes` hint
 * assume `100vw`, which causes them to pick the widest entry in the srcSet
 * ladder even on small viewports. These defaults match the typical layout
 * each variant is used in - callers can override via the `sizes` prop.
 */
const DEFAULT_SIZES = DEFAULT_IMAGE_SIZES;

/** Props for the Image component */
export interface ImageProps extends Omit<
  React.ImgHTMLAttributes<HTMLImageElement>,
  | 'src'
  | 'alt'
  | 'width'
  | 'height'
  | 'loading'
  | 'sizes'
  | 'className'
  | 'style'
  | 'onError'
  | 'fetchPriority'
> {
  /**
   * Cloudflare Images ID or full URL.
   * Used to build AVIF/WebP/JPEG variants via Cloudflare Images.
   */
  src: string;
  /**
   * Alt text - REQUIRED for accessibility.
   * @throws In development if alt is empty/missing and `decorative` is not true.
   */
  alt: string;
  /** Width in pixels. */
  width?: number;
  /** Height in pixels. */
  height?: number;
  /** Loading strategy. Defaults to 'lazy'. Above-fold: use 'eager'. */
  loading?: 'lazy' | 'eager';
  /** Fetch priority hint. Above-fold hero: use 'high'. */
  fetchpriority?: 'high' | 'low' | 'auto';
  /** Sizes attribute for responsive images. */
  sizes?: string;
  /**
   * Image size/purpose variant. Controls which Cloudflare Images variant is requested.
   * 'og' variant uses WebP as primary (no AVIF - Facebook/WhatsApp don't support it).
   * @default 'card'
   */
  variant?: ImageVariant;
  /** When true, marks as decorative - skips the dev alt-text check and sets aria-hidden. */
  decorative?: boolean;
  /** Additional class names on the `<img>` element. */
  className?: string;
  /** Inline styles on the `<img>` element (e.g. objectPosition). */
  style?: React.CSSProperties;
  /** Custom error handler — called when the image fails to load (e.g. 404 in dev). */
  onError?: React.ReactEventHandler<HTMLImageElement>;
  /**
   * When true, bypasses variant URL building and renders src directly.
   * Use for admin/moderation contexts where originals must be shown as-is.
   */
  raw?: boolean;
}

/**
 * Multideal Image primitive - the critical AVIF pipeline wrapper.
 *
 * Emits a single `<img srcset sizes>` element. AVIF is universal in 2026.
 * Falls back gracefully if `IMAGES_ACCOUNT_HASH` is not configured.
 *
 * OG variant (`variant="og"`) uses WebP as primary - AVIF is not supported
 * by Facebook/WhatsApp OG scrapers.
 *
 * @example
 * ```tsx
 * // Lazy card image
 * <Image src={deal.imageId} alt={deal.title} width={400} height={300} variant="card" />
 *
 * // Above-fold hero
 * <Image src={hero.imageId} alt={hero.alt} loading="eager" fetchpriority="high" variant="hero" />
 *
 * // Decorative
 * <Image src={pattern.id} alt="" decorative />
 * ```
 */
export function Image({
  src,
  alt,
  width,
  height,
  loading = 'lazy',
  fetchpriority = 'auto',
  sizes,
  variant = 'card',
  decorative = false,
  className,
  style,
  onError,
  raw,
  ...imgProps
}: ImageProps) {
  // Alt-text guard: required unless explicitly decorative.
  // Catches both the missing-prop case and consumers that pass through nullish DB values.
  // DEV: throw to fail fast during development.
  // PROD: log to Sentry via captureCaught — never crash the page over a missing alt.
  const altIsMissing = alt == null || alt === '';
  if (!decorative && altIsMissing) {
    const message =
      '[Multideal <Image>] Missing `alt` prop. Every image requires descriptive alt text. ' +
      'If the image is purely decorative, pass `decorative={true}` and `alt=""`.';
    if (import.meta.env.DEV) {
      throw new Error(message);
    }
    captureCaught(new Error(message), {
      scope: 'ui.primitives.Image.missing-alt',
      severity: 'warning',
      extra: { src, variant },
    });
  }
  // Always emit a string alt attribute on the underlying <img> so getByRole('img')
  // never sees `alt={null}`. Decorative images get the empty string.
  const safeAlt: string = decorative || alt == null ? '' : alt;

  // Empty src - render a neutral placeholder to avoid broken requests.
  if (!src) {
    return (
      <div
        className={cn(
          'flex items-center justify-center bg-[linear-gradient(135deg,var(--color-brand-primary-50),var(--color-warning-50))] object-cover',
          className,
        )}
        style={width && height ? { width, height } : undefined}
        aria-hidden="true"
      />
    );
  }

  if (raw) {
    return (
      <img
        src={src}
        alt={safeAlt}
        width={width}
        height={height}
        loading={loading}
        fetchPriority={fetchpriority}
        aria-hidden={decorative || undefined}
        className={cn('object-cover', className)}
        style={style}
        {...imgProps}
        onError={(e) => {
          console.warn('img-404', e.currentTarget.currentSrc || e.currentTarget.src);
          onError?.(e);
        }}
      />
    );
  }

  const widths = VARIANT_MATRIX[variant].widths;
  const largest = widths[widths.length - 1]!;
  const resolvedSrc = buildVariantUrl(src, variant, largest);
  if (!resolvedSrc) {
    return (
      <div
        className={cn(
          'flex items-center justify-center bg-[linear-gradient(135deg,var(--color-brand-primary-50),var(--color-warning-50))] object-cover',
          className,
        )}
        style={width && height ? { width, height } : undefined}
        aria-hidden="true"
      />
    );
  }
  const resolvedSizes = sizes ?? DEFAULT_SIZES[variant];

  return (
    <img
      src={resolvedSrc}
      srcSet={buildSrcSet(src, variant)}
      sizes={resolvedSizes}
      alt={safeAlt}
      width={width}
      height={height}
      loading={loading}
      fetchPriority={fetchpriority}
      aria-hidden={decorative || undefined}
      className={cn('object-cover', className)}
      style={style}
      {...imgProps}
      onError={(e) => {
        console.warn('img-404', e.currentTarget.currentSrc || e.currentTarget.src);
        onError?.(e);
      }}
    />
  );
}
