export type BodySlot = 'torso' | 'legs' | 'hands' | 'feet';
export const bodySlots: BodySlot[] = ['torso', 'legs', 'hands', 'feet'];
export type BodyTextureLayers = {
  sourceMaterial: string; targetMaterials?: string[]; baseTextureUrl: string; baseUvSetIndex: number;
  decalTextureUrl: string; decalUvSetIndex: number;
  sourceAlphaProperty?: { flags: number; alphaTestEnabled: boolean; alphaCutoff: number };
};
export type MaterialRecipe = {
  slot: BodySlot; meshes: string[]; targetMaterials: string[]; textureUrl: string;
  bodyTextureLayers?: BodyTextureLayers[];
};
export type BodyRecipe = {
  id: string; itemId: string | null; label?: string; nameOriginal?: string;
  meshes: string[]; targetMaterials: string[]; textureUrl?: string;
  appearanceKind?: 'base' | 'armor' | 'outfit' | 'unresolved';
  replacementSlots?: BodySlot[]; components?: MaterialRecipe[];
  bodyTextureLayers?: BodyTextureLayers[];
};

// suitequip outfits author all four body groups. Never combine them with
// independently selected armor or base groups underneath the costume.
export function composeBody(selections: Record<BodySlot, BodyRecipe[]>, state: Record<BodySlot, string>) {
  const selected = bodySlots.map(slot => {
    const recipe = selections[slot].find(entry => entry.id === state[slot]);
    if (!recipe) throw new Error(`No existe la pieza seleccionada: ${state[slot]}`);
    return { slot, recipe };
  });
  const outfit = selected.find(({ slot, recipe }) => slot === 'torso' && recipe.appearanceKind === 'outfit');
  if (outfit) {
    if (!bodySlots.every(slot => outfit.recipe.replacementSlots?.includes(slot))
      || outfit.recipe.components?.length !== bodySlots.length
      || !bodySlots.every(slot => outfit.recipe.components!.filter(component => component.slot === slot).length === 1)) {
      throw new Error(`El outfit no contiene los cuatro grupos originales: ${outfit.recipe.id}`);
    }
  }
  const layers = outfit ? outfit.recipe.components!.map(recipe => ({ slot: recipe.slot, recipe, owner: outfit.recipe }))
    : selected.map(({ slot, recipe }) => {
      if (!recipe.textureUrl) throw new Error(`Falta la textura original de ${recipe.id}`);
      return { slot, recipe: { slot, meshes: recipe.meshes, targetMaterials: recipe.targetMaterials,
        textureUrl: recipe.textureUrl, bodyTextureLayers: recipe.bodyTextureLayers }, owner: recipe };
    });
  const replacedSlots: BodySlot[] = outfit ? bodySlots.filter(slot => slot !== 'torso') : [];
  return { layers, outfit: outfit?.recipe ?? null, replacedSlots };
}
