/**
 * Canonical identity helpers for catalog product-3d elements and their runtime
 * Babylon instances. Runtime instance ids are deliberately not used to match a
 * catalog element because a new id is generated for every placement.
 */
const cleanIdentity = (value: unknown): string => String(value ?? '').trim();
const firstIdentity = (...values: unknown[]): string => values.map(cleanIdentity).find(Boolean) ?? '';

export const getProduct3DElementId = (element: any): string => cleanIdentity(element?.id);
export const getProduct3DElementName = (element: any): string => cleanIdentity(element?.name);
export const getProduct3DElementFamilyId = (element: any): string => cleanIdentity(element?.familyId);

export const getProduct3DMeshInstanceId = (mesh: any): string => firstIdentity(
  mesh?.metadata?.asukaProductId,
  mesh?.metadata?.productId,
);

export const getProduct3DInstanceCatalogId = (product: any): string => firstIdentity(
  product?.catalogId,
  product?.metadata?.elementId,
  product?.metadata?.catalogId,
);

export const getProduct3DInstanceFamilyId = (product: any): string => firstIdentity(
  product?.metadata?.elementFamilyId,
  product?.metadata?.familyId,
);

export const getProduct3DElementStableKey = (element: any): string => (
  getProduct3DElementId(element)
  || getProduct3DElementFamilyId(element)
);

/** Match an instance to one catalog element using immutable catalog/family ids. */
export const product3DInstanceMatchesElement = (product: any, element: any): boolean => {
  const productCatalogId = getProduct3DInstanceCatalogId(product);
  const elementId = getProduct3DElementId(element);
  if (productCatalogId && elementId) return productCatalogId === elementId;

  const productFamilyId = getProduct3DInstanceFamilyId(product);
  const elementFamilyId = getProduct3DElementFamilyId(element);
  if (productFamilyId && elementFamilyId) return productFamilyId === elementFamilyId;

  return false;
};

/** Resolve one catalog record without silently choosing between duplicate names. */
export const findCatalogProduct3DElementForInstance = (catalogInput: any[], product: any): any | null => {
  const catalog = (Array.isArray(catalogInput) ? catalogInput : []).filter(Boolean);
  const productCatalogId = getProduct3DInstanceCatalogId(product);
  if (productCatalogId) {
    const byId = catalog.find((element) => getProduct3DElementId(element) === productCatalogId);
    if (byId) return byId;
  }

  const productFamilyId = getProduct3DInstanceFamilyId(product);
  if (productFamilyId) {
    const familyMatches = catalog.filter((element) => getProduct3DElementFamilyId(element) === productFamilyId);
    if (familyMatches.length === 1) return familyMatches[0];
  }

  return null;
};

/**
 * Variations may propagate between placements of the same catalog element and
 * explicit copies in the same family, never to an unrelated product merely
 * because it happens to contain a variation named "Red" or "Blue".
 */
export const product3DElementsShareVariationFamily = (left: any, right: any): boolean => {
  if (!left || !right) return false;
  const leftId = getProduct3DElementId(left);
  const rightId = getProduct3DElementId(right);
  if (leftId && rightId && leftId === rightId) return true;

  const leftFamilyId = getProduct3DElementFamilyId(left);
  const rightFamilyId = getProduct3DElementFamilyId(right);
  return !!leftFamilyId && !!rightFamilyId && leftFamilyId === rightFamilyId;
};

export const countProduct3DInstancesForElement = (productsInput: any[], element: any): number => (
  (Array.isArray(productsInput) ? productsInput : [])
    .filter((product) => product3DInstanceMatchesElement(product, element))
    .length
);

/** Resolve the runtime instance explicitly carried by a Babylon canvas pick. */
export const getProduct3DCanvasSelectionInstanceId = (selected: any): string => {
  const metadataId = firstIdentity(
    selected?.metadata?.asukaProductId,
    selected?.metadata?.productId,
  );
  if (metadataId) return metadataId.replace(/^product:/i, '').trim();

  const selectedId = cleanIdentity(selected?.id);
  if (!/^product:/i.test(selectedId)) return '';
  const instanceId = selectedId.replace(/^product:/i, '').trim();
  return instanceId && instanceId.toLowerCase() !== 'current' ? instanceId : '';
};

/**
 * Resolve the product attached to a canvas click without leaking the scene's
 * previously selected product into an explicit click on another instance.
 */
export const resolveProduct3DCanvasSelectionInstance = (selected: any, scene: any): any | null => {
  const products = Array.isArray(scene?.products) ? scene.products : [];
  const explicitInstanceId = getProduct3DCanvasSelectionInstanceId(selected);
  const directProduct = selected?.metadata?.product && typeof selected.metadata.product === 'object'
    ? selected.metadata.product
    : null;

  if (explicitInstanceId) {
    const exactSceneProduct = products.find((product: any) => cleanIdentity(product?.id) === explicitInstanceId);
    if (exactSceneProduct) return exactSceneProduct;
    return directProduct;
  }

  if (directProduct) {
    const directId = cleanIdentity(directProduct?.id);
    return products.find((product: any) => directId && cleanIdentity(product?.id) === directId) ?? directProduct;
  }

  const selectedProductId = cleanIdentity(scene?.selectedProductId);
  if (selectedProductId) {
    const selectedProduct = products.find((product: any) => cleanIdentity(product?.id) === selectedProductId);
    if (selectedProduct) return selectedProduct;
  }

  return products.length === 1 ? products[0] : null;
};
