export type Product3DVariationTargetMesh = {
  id?: unknown;
  name?: unknown;
  metadata?: {
    asukaProductId?: unknown;
    asukaOriginalMeshId?: unknown;
    asukaOriginalMeshName?: unknown;
    sourceMeshId?: unknown;
    sourceMeshName?: unknown;
  } | null;
};

const clean = (value: unknown): string => String(value ?? '').trim();

const toStringList = (value: unknown): string[] => {
  if (Array.isArray(value)) return value.map(clean).filter(Boolean);
  return clean(value).split(',').map((item) => item.trim()).filter(Boolean);
};

const getMeshAliases = (mesh: Product3DVariationTargetMesh): string[] => Array.from(new Set([
  mesh?.id,
  mesh?.name,
  mesh?.metadata?.asukaOriginalMeshId,
  mesh?.metadata?.asukaOriginalMeshName,
  mesh?.metadata?.sourceMeshId,
  mesh?.metadata?.sourceMeshName,
].map(clean).filter(Boolean)));

const resolveMeshId = (mesh: Product3DVariationTargetMesh): string => clean(mesh?.id) || clean(mesh?.name);

/**
 * Keep a variation's real mesh targets scoped to the requested product.
 * A material-state key (for example instance::part) is only used as a mesh
 * target when a Babylon mesh with that exact id/name genuinely exists.
 */
export const resolveProduct3DVariationTargetMeshIds = (input: {
  material?: any;
  targetInstanceId?: unknown;
  materialTarget?: unknown;
  meshes?: Product3DVariationTargetMesh[] | null;
}): string[] => {
  const variationTargetMeshIds = toStringList(
    input?.material?.targetMeshIds
    ?? input?.material?.metadata?.targetMeshIds,
  );
  const instanceId = clean(input?.targetInstanceId);
  const meshes = Array.isArray(input?.meshes) ? input.meshes : [];

  const matchingMeshes = (target: string): Product3DVariationTargetMesh[] => meshes.filter((mesh) => {
    if (instanceId && clean(mesh?.metadata?.asukaProductId) !== instanceId) return false;
    return getMeshAliases(mesh).includes(target);
  });

  const scopedTargetMeshIds = variationTargetMeshIds.flatMap((target) => {
    const matches = matchingMeshes(target).map(resolveMeshId).filter(Boolean);
    if (matches.length) return matches;
    if (!instanceId || target.includes(`${instanceId}::`)) return [target];
    return [];
  });

  if (scopedTargetMeshIds.length) return Array.from(new Set(scopedTargetMeshIds));

  const materialTarget = clean(input?.materialTarget);
  if (materialTarget) {
    const materialMatches = matchingMeshes(materialTarget).map(resolveMeshId).filter(Boolean);
    if (materialMatches.length) return Array.from(new Set(materialMatches));
  }

  return instanceId ? [] : Array.from(new Set(variationTargetMeshIds));
};
