import type { ElementVariation } from '../types/elements';

export type ElementVariationPreviewKind = 'image' | 'color' | 'texture' | 'fallback';

export type ElementVariationPreview = {
  kind: ElementVariationPreviewKind;
  value: string;
};

export const ELEMENT_VARIATION_FALLBACK_COLOR = '#d7dde8';

const nonEmpty = (...values: unknown[]): string => {
  for (const value of values) {
    const normalized = String(value ?? '').trim();
    if (normalized) return normalized;
  }
  return '';
};

const isLikelyCssColor = (value: unknown): value is string => {
  const color = String(value ?? '').trim();
  return Boolean(color && (
    /^#(?:[0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(color)
    || /^(?:rgb|rgba|hsl|hsla)\(/i.test(color)
    || /^var\(/i.test(color)
    || /^[a-z]+$/i.test(color)
  ));
};

export const getElementVariationExplicitPreviewSource = (variation: any): string => {
  const product3d = variation?.product3d && typeof variation.product3d === 'object' ? variation.product3d : {};
  return nonEmpty(
    variation?.image,
    variation?.icon,
    product3d?.preview?.url,
    product3d?.previewUrl,
    product3d?.thumbnailUrl,
  );
};

const getVariationMaterial = (variation: any): any => {
  const product3d = variation?.product3d && typeof variation.product3d === 'object' ? variation.product3d : {};
  const materials = product3d?.materials && typeof product3d.materials === 'object' ? product3d.materials : {};
  const target = String(product3d?.materialTarget ?? '').trim();
  const fallbackTarget = Object.keys(materials)[0] ?? '';
  return materials[target] ?? materials[fallbackTarget] ?? {};
};

const resolveVariationColor = (variation: any, material: any): string => {
  const candidates = [
    variation?.color,
    variation?.fill,
    variation?.background,
    variation?.backgroundColor,
    variation?.style?.color,
    variation?.style?.fill,
    variation?.style?.background,
    variation?.style?.backgroundColor,
    variation?.metadata?.color,
    variation?.metadata?.fill,
    variation?.product3d?.color,
    variation?.product3d?.fill,
    material?.color,
    material?.fill,
    material?.albedoColor,
    material?.diffuseColor,
    material?.baseColor,
  ];

  for (const candidate of candidates) {
    if (isLikelyCssColor(candidate)) return String(candidate).trim();
  }
  return '';
};

const resolveVariationTexture = (variation: any, material: any): string => nonEmpty(
  variation?.textureUrl,
  variation?.texture,
  variation?.metadata?.textureUrl,
  variation?.product3d?.textureUrl,
  material?.textureUrl,
  material?.albedoTextureUrl,
  material?.diffuseTextureUrl,
  material?.baseColorTextureUrl,
);

/**
 * Resolves the visual shown for one variation-tree level.
 *
 * Preview data is deliberately local to the node. A parent image must not
 * replace a child color/texture, and a child image must not bubble up to its
 * group. The runtime can still merge a variation path when applying it; that
 * inheritance is unrelated to the customer-facing thumbnail.
 */
export const resolveElementVariationPreview = (
  variation: ElementVariation | any,
  _variationPath?: Array<ElementVariation | any>,
): ElementVariationPreview => {
  const image = getElementVariationExplicitPreviewSource(variation);
  if (image) return { kind: 'image', value: image };

  const material = getVariationMaterial(variation);
  const color = resolveVariationColor(variation, material);
  if (color) return { kind: 'color', value: color };

  const texture = resolveVariationTexture(variation, material);
  if (texture) return { kind: 'texture', value: texture };

  return { kind: 'fallback', value: ELEMENT_VARIATION_FALLBACK_COLOR };
};
