/* ────────────────────────────────────────────────────────────────
   IconSprite — Bridge between @nice2dev/icons-gaming SVG icons
   and the game-engine Canvas 2D renderer.

   Converts React SVG icon components to rasterized textures that
   can be used as Sprite assets, including multi-frame animation
   sheets generated from different animation states.
──────────────────────────────────────────────────────────────── */
/* ── SVG to Image conversion ──────────────────────────────────── */
/**
 * Render an icon component to an SVG string using React's static markup API.
 * This function must be called with the result of ReactDOMServer.renderToStaticMarkup().
 */
function iconToSvgString(svgMarkup, size) {
    // Ensure SVG has xmlns for standalone rendering
    if (!svgMarkup.includes('xmlns=')) {
        svgMarkup = svgMarkup.replace('<svg', '<svg xmlns="http://www.w3.org/2000/svg"');
    }
    // Ensure dimensions
    if (!svgMarkup.includes('width=')) {
        svgMarkup = svgMarkup.replace('<svg', `<svg width="${size}" height="${size}"`);
    }
    return svgMarkup;
}
/**
 * Convert an SVG string to a data URL suitable for Image loading.
 */
function svgToDataUrl(svgString) {
    const encoded = encodeURIComponent(svgString)
        .replace(/'/g, '%27')
        .replace(/"/g, '%22');
    return `data:image/svg+xml,${encoded}`;
}
/**
 * Load an SVG data URL into an HTMLImageElement (async).
 */
function loadSvgImage(dataUrl) {
    return new Promise((resolve, reject) => {
        const img = new Image();
        img.onload = () => resolve(img);
        img.onerror = () => reject(new Error('Failed to load SVG image'));
        img.src = dataUrl;
    });
}
/**
 * Rasterize an SVG string to an OffscreenCanvas / HTMLCanvasElement.
 */
async function rasterizeSvg(svgString, size) {
    const dataUrl = svgToDataUrl(svgString);
    const img = await loadSvgImage(dataUrl);
    const canvas = document.createElement('canvas');
    canvas.width = size;
    canvas.height = size;
    const ctx = canvas.getContext('2d');
    if (!ctx)
        throw new Error('Failed to get 2D context');
    ctx.drawImage(img, 0, 0, size, size);
    return canvas;
}
/* ── Texture registration ─────────────────────────────────────── */
/**
 * Generate a deterministic texture ID for an icon + options combination.
 */
function getIconTextureId(displayName, options) {
    const parts = [`icon:${displayName}`];
    if (options === null || options === void 0 ? void 0 : options.size)
        parts.push(`s${options.size}`);
    if (options === null || options === void 0 ? void 0 : options.color)
        parts.push(`c${options.color}`);
    if ((options === null || options === void 0 ? void 0 : options.animation) && options.animation !== 'none')
        parts.push(`a${options.animation}`);
    return parts.join(':');
}
/**
 * Register an SVG icon as a texture in the game-engine renderer.
 *
 * @param renderer  The Renderer2D instance
 * @param textureId Unique texture identifier
 * @param svgMarkup Static SVG markup from ReactDOMServer.renderToStaticMarkup(<Icon ... />)
 * @param size      Rasterization size in px
 * @returns         Promise that resolves when the texture is ready
 *
 * @example
 * ```ts
 * import { renderToStaticMarkup } from 'react-dom/server';
 * import { GiWarrior } from '@nice2dev/icons-gaming';
 * import { registerIconTexture, getIconTextureId } from '@nice2dev/game-engine';
 *
 * const id = getIconTextureId('GiWarrior', { size: 64 });
 * const svg = renderToStaticMarkup(<GiWarrior size={64} color="#e74c3c" />);
 * await registerIconTexture(renderer, id, svg, 64);
 * ```
 */
async function registerIconTexture(renderer, textureId, svgMarkup, size) {
    const existing = renderer.getTexture(textureId);
    if (existing)
        return; // already loaded
    const prepared = iconToSvgString(svgMarkup, size);
    const dataUrl = svgToDataUrl(prepared);
    await renderer.loadTexture(textureId, dataUrl);
}
/**
 * Register an SVG icon as a rasterized canvas texture (sync-safe after await).
 * Useful when you need pixel-perfect rendering without scaling artifacts.
 */
async function registerIconCanvasTexture(renderer, textureId, svgMarkup, size) {
    const existing = renderer.getTexture(textureId);
    if (existing)
        return;
    const prepared = iconToSvgString(svgMarkup, size);
    const canvas = await rasterizeSvg(prepared, size);
    renderer.setTexture(textureId, canvas);
}
/* ── Entity helpers ───────────────────────────────────────────── */
/**
 * Create a game entity with Sprite component sourced from an icon texture.
 *
 * The texture must already be registered via `registerIconTexture()`.
 *
 * @example
 * ```ts
 * const entityId = createIconEntity(world, 'GiWarrior', textureId, {
 *   x: 200, y: 150, displayWidth: 64, displayHeight: 64, layer: 1,
 * });
 * ```
 */
function createIconEntity(world, name, textureId, options) {
    var _a, _b, _c, _d, _e, _f;
    const entity = world.createEntity((_a = options === null || options === void 0 ? void 0 : options.name) !== null && _a !== void 0 ? _a : name);
    entity.tags.add('icon-sprite');
    world.addComponent(entity.id, 'Transform', {
        position: { x: (_b = options === null || options === void 0 ? void 0 : options.x) !== null && _b !== void 0 ? _b : 0, y: (_c = options === null || options === void 0 ? void 0 : options.y) !== null && _c !== void 0 ? _c : 0 },
        scale: { x: 1, y: 1 },
    });
    const spriteOverrides = {
        assetId: textureId,
        width: (_d = options === null || options === void 0 ? void 0 : options.displayWidth) !== null && _d !== void 0 ? _d : 32,
        height: (_e = options === null || options === void 0 ? void 0 : options.displayHeight) !== null && _e !== void 0 ? _e : 32,
        layer: (_f = options === null || options === void 0 ? void 0 : options.layer) !== null && _f !== void 0 ? _f : 0,
        visible: true,
    };
    if (options === null || options === void 0 ? void 0 : options.tint)
        spriteOverrides.tint = options.tint;
    if ((options === null || options === void 0 ? void 0 : options.opacity) !== undefined)
        spriteOverrides.opacity = options.opacity;
    world.addComponent(entity.id, 'Sprite', spriteOverrides);
    return entity.id;
}
/* ── Animation sheet helpers ──────────────────────────────────── */
/**
 * Create a SpriteAnimation clip from multiple icon animation frames.
 *
 * Each frame is a separate registered texture. The AnimatorComponent
 * switches `assetId` each frame to show different icon states.
 *
 * @param frames  Array of { assetId, duration } for each frame
 * @param loop    Whether animation loops
 */
function createIconAnimationClip(frames, fps = 8, loop = true) {
    return {
        frames: frames.map(f => ({
            assetId: f.assetId,
            srcRect: null,
            duration: f.duration,
        })),
        fps,
        loop,
    };
}
/**
 * Predefined character animation state sequences.
 * Maps game animation concepts to sets of icon animation states
 * that can be baked into textures.
 */
const CHARACTER_ANIMATION_STATES = [
    'idle', 'move', 'jump', 'attack-melee', 'attack-ranged', 'attack-magic', 'damage', 'death',
];
const OBJECT_ANIMATION_STATES = [
    'idle', 'spin', 'float', 'shake', 'glow', 'bounce', 'flicker',
];
/**
 * Batch-register all animation states of an icon as separate textures.
 *
 * @returns Map of animation state → texture ID
 *
 * @example
 * ```ts
 * const textures = await registerIconAnimationSet(
 *   renderer,
 *   'GiWarrior',
 *   (anim) => renderToStaticMarkup(<GiWarrior size={64} animation={anim} color="#e74c3c" />),
 *   CHARACTER_ANIMATION_STATES,
 *   64,
 * );
 * // textures = { idle: 'icon:GiWarrior:s64:aidle', move: 'icon:GiWarrior:s64:amove', ... }
 * ```
 */
async function registerIconAnimationSet(renderer, displayName, renderFn, states, size) {
    const result = {};
    for (const state of states) {
        const textureId = getIconTextureId(displayName, { size, animation: state });
        const svgMarkup = renderFn(state);
        await registerIconTexture(renderer, textureId, svgMarkup, size);
        result[state] = textureId;
    }
    return result;
}
/**
 * Create an Animator component configuration from a registered animation set.
 *
 * @param textureMap Result from `registerIconAnimationSet()`
 * @param defaultState Initial animation state (default: 'idle')
 * @param fps Frames per second for each clip
 */
function createIconAnimator(textureMap, defaultState = 'idle', fps = 1) {
    const animations = {};
    for (const [state, assetId] of Object.entries(textureMap)) {
        animations[state] = {
            frames: [{ assetId, srcRect: null }],
            fps,
            loop: true,
        };
    }
    return {
        currentAnimation: defaultState,
        animations,
        frame: 0,
        elapsed: 0,
        playing: true,
        loop: true,
    };
}
/**
 * Register an entire icon map (e.g. `characterIcons`, `weaponIcons`)
 * and return a catalog array for the asset manager / picker.
 *
 * @param renderer   Renderer2D
 * @param iconMap    Map of name→icon render functions (SVG markup generators)
 * @param category   Category label for the asset catalog
 * @param size       Texture size
 *
 * @example
 * ```ts
 * const catalog = await registerIconCatalog(
 *   renderer,
 *   {
 *     GiWarrior: () => renderToStaticMarkup(<GiWarrior size={64} color="#e74c3c" />),
 *     GiMage: () => renderToStaticMarkup(<GiMage size={64} color="#3498db" />),
 *   },
 *   'characters',
 *   64,
 * );
 * ```
 */
async function registerIconCatalog(renderer, iconMap, category, size) {
    const catalog = [];
    for (const [name, renderFn] of Object.entries(iconMap)) {
        const textureId = getIconTextureId(name, { size });
        await registerIconTexture(renderer, textureId, renderFn(), size);
        catalog.push({ name, textureId, category });
    }
    return catalog;
}

export { CHARACTER_ANIMATION_STATES, OBJECT_ANIMATION_STATES, createIconAnimationClip, createIconAnimator, createIconEntity, getIconTextureId, iconToSvgString, loadSvgImage, rasterizeSvg, registerIconAnimationSet, registerIconCanvasTexture, registerIconCatalog, registerIconTexture, svgToDataUrl };
//# sourceMappingURL=IconSprite.js.map
