import { jsx, jsxs } from 'react/jsx-runtime';
import { useState, useRef, useEffect, useMemo, useCallback } from 'react';
import styles from './PixelEditor.module.css.js';
import { NiceModal as Ys, NiceButton as We, NiceSelect as fn, NiceNumberInput as ir, NiceCheckbox as Fr } from '../packages/ui/dist/index.js';
import { getAllParts, assembleSprite, applyIsometricProjection, getPart, generateAllDirections, render8DirSpriteSheet, getPartsByCategory, ALL_DIRECTIONS } from './spriteGeneratorCore.js';
import { CHARACTER_PRESETS, initCharacterParts, SKIN_PALETTES, HAIR_PALETTES, CLOTHING_PALETTES } from './characterGeneratorPresets.js';
import { BUILDING_PRESETS, assembleBuildingFromConfig, initBuildingParts, WALL_PALETTES, ROOF_PALETTES } from './buildingGeneratorPresets.js';
import { ANIMAL_PRESETS, initAnimalParts, FUR_PALETTES } from './animalGeneratorPresets.js';

/* ════════════════════════════════════════════════════════════════
   INITIALIZATION
   ════════════════════════════════════════════════════════════════ */
let _initialized = false;
function ensureInitialized() {
    if (_initialized)
        return;
    _initialized = true;
    initCharacterParts();
    initBuildingParts();
    initAnimalParts();
}
/* ════════════════════════════════════════════════════════════════
   HELPERS
   ════════════════════════════════════════════════════════════════ */
function palettesToOptions(palettes) {
    return Object.entries(palettes).map(([id, colors]) => ({
        id,
        name: id.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase()),
        colors,
    }));
}
const CHAR_CATEGORIES = [
    'head', 'hair', 'face', 'torso', 'arm', 'leg', 'hat', 'helmet', 'armor', 'cape', 'weapon', 'shield',
];
const BUILDING_CATEGORIES = [
    'foundation', 'wall', 'floor', 'roof', 'door', 'window', 'chimney', 'decoration',
];
const ANIMAL_CATEGORIES = [
    'animalHead', 'animalBody', 'animalLeg', 'animalTail', 'animalWing', 'animalMane',
];
const NiceSpriteGeneratorPanel = ({ onSendToCanvas, onClose, }) => {
    ensureInitialized();
    /* ── State ── */
    const [tab, setTab] = useState('character');
    const [selectedPresetIdx, setSelectedPresetIdx] = useState(0);
    const [selectedParts, setSelectedParts] = useState([]);
    const [canvasW, setCanvasW] = useState(32);
    const [canvasH, setCanvasH] = useState(32);
    const [direction, setDirection] = useState('S');
    const [projection, setProjection] = useState('topDown');
    const [generate8Dir, setGenerate8Dir] = useState(false);
    // Color overrides
    const [skinPalette, setSkinPalette] = useState('light');
    const [hairPalette, setHairPalette] = useState('brown');
    const [clothPalette, setClothPalette] = useState('leather');
    const [furPalette, setFurPalette] = useState('orange');
    const [wallPalette, setWallPalette] = useState('grey_stone');
    const [roofPalette, setRoofPalette] = useState('terracotta');
    const previewRef = useRef(null);
    const partsMapRef = useRef(new Map());
    /* ── Build parts map ── */
    useEffect(() => {
        const map = new Map();
        for (const p of getAllParts())
            map.set(p.id, p);
        partsMapRef.current = map;
    }, []);
    /* ── Get presets for current tab ── */
    const presets = useMemo(() => {
        switch (tab) {
            case 'character': return CHARACTER_PRESETS;
            case 'building': return BUILDING_PRESETS;
            case 'animal': return ANIMAL_PRESETS;
        }
    }, [tab]);
    /* ── Apply preset ── */
    const applyPreset = useCallback((presetIdx) => {
        setSelectedPresetIdx(presetIdx);
        const preset = presets[presetIdx];
        if (!preset)
            return;
        if (tab === 'building') {
            const bp = preset;
            const assembly = assembleBuildingFromConfig(bp.config);
            setSelectedParts(assembly.parts);
            setCanvasW(assembly.canvasWidth);
            setCanvasH(assembly.canvasHeight);
        }
        else {
            const cp = preset;
            const assembly = cp.assembly;
            setSelectedParts([...assembly.parts]);
            setCanvasW(assembly.canvasWidth);
            setCanvasH(assembly.canvasHeight);
        }
    }, [tab, presets]);
    /* ── Initial preset ── */
    useEffect(() => {
        applyPreset(0);
    }, [tab, applyPreset]);
    /* ── Build current assembly ── */
    const currentAssembly = useMemo(() => {
        var _a;
        return ({
            id: `gen_${tab}_${selectedPresetIdx}`,
            name: ((_a = presets[selectedPresetIdx]) === null || _a === void 0 ? void 0 : _a.name) || 'Custom',
            parts: selectedParts,
            canvasWidth: canvasW,
            canvasHeight: canvasH,
            projection,
        });
    }, [tab, selectedPresetIdx, selectedParts, canvasW, canvasH, projection, presets]);
    /* ── Render preview ── */
    useEffect(() => {
        const canvas = previewRef.current;
        if (!canvas)
            return;
        const img = assembleSprite(currentAssembly, partsMapRef.current, direction);
        let finalImg = img;
        if (projection === 'iso25d') {
            finalImg = applyIsometricProjection(img);
        }
        canvas.width = finalImg.width;
        canvas.height = finalImg.height;
        const ctx = canvas.getContext('2d');
        if (ctx) {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            ctx.putImageData(finalImg, 0, 0);
        }
    }, [currentAssembly, direction, projection]);
    /* ── Toggle part visibility ── */
    const togglePart = useCallback((partId) => {
        setSelectedParts(prev => prev.map(p => { var _a; return p.partId === partId ? { ...p, visible: !((_a = p.visible) !== null && _a !== void 0 ? _a : true) } : p; }));
    }, []);
    /* ── Add part ── */
    const addPart = useCallback((partId) => {
        if (selectedParts.some(p => p.partId === partId))
            return;
        const part = getPart(partId);
        if (!part)
            return;
        setSelectedParts(prev => {
            var _a, _b, _c, _d;
            return [...prev, {
                    partId,
                    offsetX: Math.floor(canvasW / 2) - Math.floor(((_b = (_a = part.pixels.S) === null || _a === void 0 ? void 0 : _a.width) !== null && _b !== void 0 ? _b : 8) / 2),
                    offsetY: Math.floor(canvasH / 2) - Math.floor(((_d = (_c = part.pixels.S) === null || _c === void 0 ? void 0 : _c.height) !== null && _d !== void 0 ? _d : 8) / 2),
                    visible: true,
                }];
        });
    }, [selectedParts, canvasW, canvasH]);
    /* ── Remove part ── */
    const removePart = useCallback((partId) => {
        setSelectedParts(prev => prev.filter(p => p.partId !== partId));
    }, []);
    /* ── Send to canvas ── */
    const handleSendToCanvas = useCallback(() => {
        if (generate8Dir) {
            const frames = generateAllDirections(currentAssembly, partsMapRef.current);
            const sheet = render8DirSpriteSheet(frames);
            onSendToCanvas(sheet);
        }
        else {
            let img = assembleSprite(currentAssembly, partsMapRef.current, direction);
            if (projection === 'iso25d') {
                img = applyIsometricProjection(img);
            }
            onSendToCanvas(img);
        }
        onClose();
    }, [generate8Dir, currentAssembly, direction, projection, onSendToCanvas, onClose]);
    /* ── Categories for current tab ── */
    const categories = useMemo(() => {
        switch (tab) {
            case 'character': return CHAR_CATEGORIES;
            case 'building': return BUILDING_CATEGORIES;
            case 'animal': return ANIMAL_CATEGORIES;
        }
    }, [tab]);
    /* ── Available palette options ── */
    const paletteGroups = useMemo(() => {
        switch (tab) {
            case 'character': return [
                { label: 'Skin', options: palettesToOptions(SKIN_PALETTES), value: skinPalette, set: setSkinPalette },
                { label: 'Hair', options: palettesToOptions(HAIR_PALETTES), value: hairPalette, set: setHairPalette },
                { label: 'Clothing', options: palettesToOptions(CLOTHING_PALETTES), value: clothPalette, set: setClothPalette },
            ];
            case 'building': return [
                { label: 'Walls', options: palettesToOptions(WALL_PALETTES), value: wallPalette, set: setWallPalette },
                { label: 'Roof', options: palettesToOptions(ROOF_PALETTES), value: roofPalette, set: setRoofPalette },
            ];
            case 'animal': return [
                { label: 'Fur', options: palettesToOptions(FUR_PALETTES), value: furPalette, set: setFurPalette },
            ];
        }
    }, [tab, skinPalette, hairPalette, clothPalette, wallPalette, roofPalette, furPalette]);
    /* ── Render ── */
    return (jsx(Ys, { open: true, onClose: onClose, title: "Sprite Generator", children: jsxs("div", { className: styles.genPanel, children: [jsxs("div", { className: styles.genHeader, children: [jsx("h3", { children: "Sprite Generator" }), jsx(We, { className: styles.btnIcon, variant: "ghost", size: "sm", onClick: onClose, title: "Close", children: "\u2715" })] }), jsx("div", { className: styles.genTabs, children: ['character', 'building', 'animal'].map(t => (jsxs(We, { className: `${styles.genTabBtn} ${tab === t ? styles.genTabBtnActive : ''}`, variant: tab === t ? 'primary' : 'ghost', size: "sm", onClick: () => setTab(t), children: [t === 'character' ? '🧑' : t === 'building' ? '🏠' : '🐾', ' ', t.charAt(0).toUpperCase() + t.slice(1)] }, t))) }), jsxs("div", { className: styles.genBody, children: [jsxs("div", { className: styles.genLeft, children: [jsxs("div", { className: styles.panelSection, children: [jsx("div", { className: styles.panelTitle, children: jsx("span", { children: "Presets" }) }), jsx("div", { className: styles.genPresetGrid, children: presets.map((preset, i) => (jsx(We, { className: `${styles.genPresetBtn} ${i === selectedPresetIdx ? styles.genPresetBtnActive : ''}`, variant: i === selectedPresetIdx ? 'primary' : 'ghost', size: "sm", onClick: () => applyPreset(i), title: preset.name, children: preset.name }, i))) })] }), jsxs("div", { className: styles.panelSection, style: { flex: 1, overflowY: 'auto' }, children: [jsx("div", { className: styles.panelTitle, children: jsx("span", { children: "Parts" }) }), categories.map(cat => {
                                            const parts = getPartsByCategory(cat);
                                            if (parts.length === 0)
                                                return null;
                                            return (jsxs("div", { style: { marginBottom: 6 }, children: [jsx("div", { style: { fontSize: 9, color: 'var(--gray-600)', marginBottom: 2, textTransform: 'uppercase' }, children: cat.replace(/([A-Z])/g, ' $1').trim() }), jsx("div", { className: styles.genPartGrid, children: parts.map(part => {
                                                            const active = selectedParts.some(p => { var _a; return p.partId === part.id && ((_a = p.visible) !== null && _a !== void 0 ? _a : true); });
                                                            return (jsx(We, { className: `${styles.miniBtn} ${active ? styles.miniBtnActive : ''}`, variant: active ? 'primary' : 'ghost', size: "sm", onClick: () => active ? removePart(part.id) : addPart(part.id), title: part.name, children: part.name.slice(0, 8) }, part.id));
                                                        }) })] }, cat));
                                        })] })] }), jsxs("div", { className: styles.genCenter, children: [jsx("div", { className: styles.genPreviewWrap, children: jsx("canvas", { ref: previewRef, className: styles.genPreviewCanvas }) }), jsx("div", { className: styles.genDirGrid, children: ALL_DIRECTIONS.map(d => (jsx(We, { className: `${styles.miniBtn} ${direction === d ? styles.miniBtnActive : ''}`, variant: direction === d ? 'primary' : 'ghost', size: "sm", onClick: () => setDirection(d), children: d }, d))) }), jsxs("div", { className: styles.genRow, children: [jsx("label", { style: { fontSize: 10, color: 'var(--gray-600)' }, children: "Projection" }), jsx(fn, { className: styles.propSelect, value: projection, onChange: val => setProjection(val), options: [
                                                { value: 'topDown', label: 'Top-Down' },
                                                { value: 'sideView', label: 'Side View' },
                                                { value: 'iso25d', label: '2.5D Isometric' },
                                            ] })] }), jsxs("div", { className: styles.genRow, children: [jsx("label", { style: { fontSize: 10, color: 'var(--gray-600)' }, children: "Size" }), jsx(ir, { className: styles.propInput, style: { width: 48 }, min: 8, max: 256, value: canvasW, onChange: val => setCanvasW(val !== null && val !== void 0 ? val : 32) }), jsx("span", { style: { fontSize: 10, color: 'var(--gray-600)' }, children: "\u00D7" }), jsx(ir, { className: styles.propInput, style: { width: 48 }, min: 8, max: 256, value: canvasH, onChange: val => setCanvasH(val !== null && val !== void 0 ? val : 32) })] }), jsx(Fr, { checked: generate8Dir, onChange: checked => setGenerate8Dir(checked), label: "Generate 8-direction sheet", className: styles.checkLabel })] }), jsxs("div", { className: styles.genRight, children: [jsxs("div", { className: styles.panelSection, children: [jsx("div", { className: styles.panelTitle, children: jsx("span", { children: "Colors" }) }), paletteGroups.map(group => {
                                            var _a;
                                            return (jsxs("div", { style: { marginBottom: 6 }, children: [jsx("div", { style: { fontSize: 9, color: 'var(--gray-600)', marginBottom: 2 }, children: group.label }), jsx(fn, { className: styles.propSelect, value: group.value, onChange: val => group.set(val), options: group.options.map(opt => ({ value: opt.id, label: opt.name })) }), jsx("div", { className: styles.genColorSwatches, children: (_a = group.options.find(o => o.id === group.value)) === null || _a === void 0 ? void 0 : _a.colors.map((c, i) => (jsx("div", { className: styles.genColorSwatch, style: { backgroundColor: c }, title: c }, i))) })] }, group.label));
                                        })] }), jsxs("div", { className: styles.panelSection, style: { flex: 1, overflowY: 'auto' }, children: [jsx("div", { className: styles.panelTitle, children: jsx("span", { children: "Assembly" }) }), selectedParts.map((ap, i) => {
                                            var _a, _b, _c, _d;
                                            const part = partsMapRef.current.get(ap.partId);
                                            return (jsxs("div", { className: styles.genAssemblyItem, children: [jsx(We, { className: styles.btnIcon, variant: "ghost", size: "sm", onClick: () => togglePart(ap.partId), title: ((_a = ap.visible) !== null && _a !== void 0 ? _a : true) ? 'Hide' : 'Show', children: ((_b = ap.visible) !== null && _b !== void 0 ? _b : true) ? '👁' : '─' }), jsx("span", { className: styles.genAssemblyName, children: (_c = part === null || part === void 0 ? void 0 : part.name) !== null && _c !== void 0 ? _c : ap.partId }), jsxs("span", { style: { fontSize: 9, color: 'var(--gray-700)' }, children: ["z:", (_d = part === null || part === void 0 ? void 0 : part.zOrder) !== null && _d !== void 0 ? _d : 0] }), jsx(We, { className: styles.btnIcon, variant: "ghost", size: "sm", onClick: () => removePart(ap.partId), title: "Remove", children: "\u2715" })] }, ap.partId));
                                        })] })] })] }), jsxs("div", { className: styles.genFooter, children: [jsx(We, { className: styles.btnSecondary, variant: "ghost", onClick: onClose, children: "Cancel" }), jsx(We, { className: styles.btnPrimary, variant: "primary", onClick: handleSendToCanvas, children: "\uD83D\uDCCB Send to Canvas" })] })] }) }));
};
NiceSpriteGeneratorPanel.displayName = 'NiceSpriteGeneratorPanel';

export { NiceSpriteGeneratorPanel as default };
//# sourceMappingURL=SpriteGeneratorPanel.js.map
