"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.applyLayerMode = applyLayerMode;
const textures_1 = require("../../textures");
const validation_1 = require("../../validation");
const entity_utils_1 = require("../../entity-utils");
const merge_overlay_1 = require("./merge-overlay");
const textured_to_voxel_1 = require("../voxels/textured-to-voxel");
const FACE_KEYS = ['north', 'south', 'east', 'west', 'top', 'bottom'];
const OVERLAY_PROPS = [
    'northOverlay',
    'southOverlay',
    'eastOverlay',
    'westOverlay',
    'topOverlay',
    'bottomOverlay',
    'sidesOverlay',
    'allOverlay',
];
const stripOverlay = (primitive) => {
    const target = primitive;
    OVERLAY_PROPS.forEach(prop => {
        target[prop] = undefined;
    });
};
const buildOverlayPrimitive = (primitive) => {
    const overlayTextures = [];
    FACE_KEYS.forEach(face => {
        const textureId = (0, textures_1.resolveOverlayFaceTextureId)(primitive, face);
        if (typeof textureId === 'string' && textureId.length > 0) {
            overlayTextures.push({ face, textureId });
        }
    });
    if (overlayTextures.length === 0) {
        return undefined;
    }
    const overlay = {
        id: `${primitive.id}_overlay_source`,
        kind: 'textured_box',
        size: primitive.size ? [...primitive.size] : [1, 1, 1],
    };
    overlayTextures.forEach(({ face, textureId }) => {
        overlay[face] = textureId;
    });
    return overlay;
};
const FACE_NAMES = ['north', 'south', 'east', 'west', 'top', 'bottom'];
const hasOverlayFaces = (primitive) => FACE_NAMES.some(face => {
    const value = primitive[face];
    return typeof value === 'string' && value.length > 0;
});
const convertPrimitiveToVoxel = (entity, primitive, mode) => {
    const textureLookup = new Map(entity.textures.map(entry => [entry.id, entry]));
    const patternLookup = new Map(entity.patterns.map(entry => [entry.id, entry]));
    const materialLookup = new Map(entity.materials.map(entry => [entry.id, entry]));
    let overlayPrimitive = buildOverlayPrimitive(primitive);
    if (overlayPrimitive && primitive.id === 'torso_primitive') {
        overlayPrimitive.top = undefined;
        overlayPrimitive.bottom = undefined;
        if (Array.isArray(overlayPrimitive.size) && overlayPrimitive.size.length >= 3) {
            overlayPrimitive.size = overlayPrimitive.size.map(value => Math.max(1, Math.round(value ?? 1) - 2));
        }
        if (!hasOverlayFaces(overlayPrimitive)) {
            overlayPrimitive = undefined;
        }
    }
    return (0, textured_to_voxel_1.convertTexturedBoxesToVoxel)({
        base: primitive,
        overlay: overlayPrimitive,
        textureLookup,
        patternLookup,
        materialLookup,
        mode,
        targetId: primitive.id,
    });
};
const transformPrimitiveLayer = (entity, primitive, mode, voxelMode) => {
    if (primitive.kind !== 'textured_box') {
        return primitive;
    }
    const textured = primitive;
    if (mode === 'overlay') {
        return textured;
    }
    if (mode === 'base_only') {
        stripOverlay(textured);
        return textured;
    }
    if (mode === 'flat') {
        (0, merge_overlay_1.mergeOverlayIntoBase)(entity, textured);
        stripOverlay(textured);
        textured.renderMode = (0, textures_1.determineTexturedBoxRenderMode)(entity, textured);
        return textured;
    }
    if (mode === 'voxel') {
        return convertPrimitiveToVoxel(entity, textured, voxelMode);
    }
    return textured;
};
const stripPrimitiveRenderMode = (primitive) => {
    if (primitive.kind === 'textured_box' && primitive.renderMode === 'cutout') {
        primitive.renderMode = undefined;
    }
};
const enforceOpaqueMaterials = (materials, fillColor, stripAlpha) => {
    if (!stripAlpha) {
        return;
    }
    const [fillR, fillG, fillB] = fillColor;
    materials.forEach(material => {
        const opacity = material.opacity ?? 1;
        if (opacity <= 0) {
            material.baseColor = [fillR, fillG, fillB];
        }
        if (material.opacity !== undefined) {
            delete material.opacity;
        }
    });
};
function applyLayerMode(entity, mode, options) {
    if (mode === 'overlay') {
        return entity;
    }
    const opts = typeof options === 'string' ? { voxelMode: options } : options ?? {};
    const voxelMode = opts.voxelMode ?? 'outer_wrap';
    const stripAlpha = opts.stripAlpha ?? false;
    const fillColor = opts.transparentFillColor ?? [0, 0, 0];
    const transformed = (0, entity_utils_1.cloneEntity)(entity);
    const primitives = [];
    transformed.primitives.forEach(primitive => {
        const result = transformPrimitiveLayer(transformed, primitive, mode, voxelMode);
        if (Array.isArray(result)) {
            primitives.push(...result);
        }
        else {
            primitives.push(result);
        }
    });
    if (mode === 'flat' && stripAlpha) {
        primitives.forEach(stripPrimitiveRenderMode);
        enforceOpaqueMaterials(transformed.materials, fillColor, stripAlpha);
    }
    transformed.primitives = primitives;
    const { issues } = (0, validation_1.validateBoxel)(transformed);
    if (issues.length > 0) {
        const summary = issues
            .slice(0, 3)
            .map(issue => `${issue.path}: ${issue.message}`)
            .join('; ');
        throw new Error(`Layer transformation produced invalid entity — ${summary}`);
    }
    return transformed;
}
//# sourceMappingURL=layer-mode.js.map