const OPTIMIZED_IMAGE_ENDPOINT = '/_img';

function trimToList(value: string | undefined | null) {
  return String(value || '')
    .split(',')
    .map((item) => item.trim().toLowerCase())
    .filter(Boolean);
}

function normalizeSrc(value: string) {
  return value.trim();
}

function getPathname(value: string) {
  try {
    return new URL(value, 'http://localhost').pathname;
  } catch {
    return value;
  }
}

export function getImageExtension(src: string) {
  const pathname = getPathname(normalizeSrc(src)).toLowerCase();
  const matched = pathname.match(/\.([a-z0-9]+)$/i);
  return matched?.[1] ?? '';
}

export function shouldOptimizeImage(src: string) {
  const normalized = normalizeSrc(src);
  if (!normalized || normalized.startsWith('data:') || normalized.startsWith('blob:')) {
    return false;
  }

  return !['svg', 'gif'].includes(getImageExtension(normalized));
}

export function isAllowedRemoteImageHost(
  src: string,
  currentOrigin: string,
  envHosts?: string,
) {
  try {
    const sourceUrl = new URL(normalizeSrc(src), currentOrigin);
    const currentHost = new URL(currentOrigin).host.toLowerCase();
    const allowedHosts = new Set([currentHost, ...trimToList(envHosts)]);
    return allowedHosts.has(sourceUrl.host.toLowerCase()) || allowedHosts.has(sourceUrl.hostname.toLowerCase());
  } catch {
    return false;
  }
}

export function canOptimizeImageSource(
  src: string,
  currentOrigin: string,
  envHosts?: string,
) {
  const normalized = normalizeSrc(src);
  if (!shouldOptimizeImage(normalized)) {
    return false;
  }

  if (normalized.startsWith('/')) {
    return true;
  }

  try {
    const sourceUrl = new URL(normalized);
    return isAllowedRemoteImageHost(sourceUrl.toString(), currentOrigin, envHosts);
  } catch {
    return false;
  }
}

export function getFallbackImageFormat(src: string): 'jpeg' | 'png' {
  return getImageExtension(src) === 'png' ? 'png' : 'jpeg';
}

export function getResponsiveWidths(widths?: number[]) {
  const defaults = [480, 768, 1024, 1440, 1920];
  const source = Array.isArray(widths) && widths.length ? widths : defaults;

  return Array.from(
    new Set(
      source
        .map((value) => Number(value))
        .filter((value) => Number.isFinite(value) && value > 0)
        .map((value) => Math.round(value)),
    ),
  ).sort((left, right) => left - right);
}

export function buildOptimizedImageUrl(
  src: string,
  options?: {
    width?: number;
    format?: 'avif' | 'webp' | 'jpeg' | 'png';
    quality?: number;
  },
) {
  const params = new URLSearchParams({
    src: normalizeSrc(src),
  });

  if (options?.width) {
    params.set('w', String(Math.round(options.width)));
  }

  if (options?.format) {
    params.set('f', options.format);
  }

  if (options?.quality) {
    params.set('q', String(Math.round(options.quality)));
  }

  return `${OPTIMIZED_IMAGE_ENDPOINT}?${params.toString()}`;
}

export function buildOptimizedSrcSet(
  src: string,
  widths: number[],
  format: 'avif' | 'webp' | 'jpeg' | 'png',
  quality?: number,
) {
  return getResponsiveWidths(widths)
    .map(
      (width) =>
        `${buildOptimizedImageUrl(src, {
          width,
          format,
          quality,
        })} ${width}w`,
    )
    .join(', ');
}
