// engine/diagram/excalidraw-generator.ts — SPEC-311: Generate Excalidraw JSON diagrams
// ---------------------------------------------------------------------------
// Internal helpers
// ---------------------------------------------------------------------------
function makeId() {
    return Math.random().toString(36).slice(2);
}
function baseElement(overrides) {
    return {
        id: makeId(),
        angle: 0,
        strokeColor: '#1e1e2e',
        backgroundColor: 'transparent',
        fillStyle: 'hachure',
        strokeWidth: 1,
        strokeStyle: 'solid',
        roughness: 1,
        opacity: 100,
        groupIds: [],
        roundness: null,
        boundElements: null,
        updated: Date.now(),
        isDeleted: false,
        link: null,
        locked: false,
        ...overrides,
    };
}
function makeRect(x, y, width, height, bg, label) {
    const rect = baseElement({
        type: 'rectangle',
        x,
        y,
        width,
        height,
        backgroundColor: bg,
        fillStyle: 'solid',
        roundness: { type: 3 },
    });
    const text = baseElement({
        type: 'text',
        x: x + 8,
        y: y + height / 2 - 10,
        width: width - 16,
        height: 20,
        text: label,
        fontSize: 14,
        fontFamily: 1,
        textAlign: 'center',
        verticalAlign: 'middle',
        strokeColor: '#ffffff',
        backgroundColor: 'transparent',
    });
    return [rect, text];
}
function makeDiamond(x, y, w, h, bg, label) {
    const diamond = baseElement({
        type: 'diamond',
        x,
        y,
        width: w,
        height: h,
        backgroundColor: bg,
        fillStyle: 'solid',
    });
    const text = baseElement({
        type: 'text',
        x: x + 8,
        y: y + h / 2 - 10,
        width: w - 16,
        height: 20,
        text: label,
        fontSize: 12,
        fontFamily: 1,
        textAlign: 'center',
        verticalAlign: 'middle',
        strokeColor: '#ffffff',
        backgroundColor: 'transparent',
    });
    return [diamond, text];
}
function makeArrow(x1, y1, x2, y2) {
    return baseElement({
        type: 'arrow',
        x: x1,
        y: y1,
        width: x2 - x1,
        height: y2 - y1,
        points: [
            [0, 0],
            [x2 - x1, y2 - y1],
        ],
        startBinding: null,
        endBinding: null,
        strokeColor: '#666666',
        roughness: 0,
    });
}
// ---------------------------------------------------------------------------
// Node parsing
// ---------------------------------------------------------------------------
/** Extract node labels from a text description. */
function parseNodes(description) {
    const separators = /->|→|--|,|\n/;
    const raw = description
        .split(separators)
        .map((s) => s.trim())
        .filter((s) => s.length > 0);
    // Deduplicate while preserving order
    const seen = new Set();
    const unique = [];
    for (const node of raw) {
        if (!seen.has(node)) {
            seen.add(node);
            unique.push(node);
        }
    }
    return unique.length > 0 ? unique : ['Node'];
}
// ---------------------------------------------------------------------------
// Layout generators per diagram type
// ---------------------------------------------------------------------------
const COLOR = {
    architecture: '#4a90d9',
    'data-flow': '#27ae60',
    sequence: '#8e44ad',
    er: '#e67e22',
    flow: '#2c3e50',
    component: '#1a73e8',
    'state-machine': '#6c3483',
    dependency: '#117a65',
    deployment: '#1b2631',
    class: '#283747',
    gantt: '#1e8449',
    pie: '#922b21',
};
const RECT_W = 150;
const RECT_H = 50;
const GAP_X = 200;
const GAP_Y = 120;
const COLS = 3;
function buildArchitecture(nodes) {
    const elements = [];
    const bg = COLOR.architecture;
    const rects = [];
    nodes.forEach((node, i) => {
        const col = i % COLS;
        const row = Math.floor(i / COLS);
        const x = col * GAP_X;
        const y = row * GAP_Y;
        rects.push({ x, y });
        elements.push(...makeRect(x, y, RECT_W, RECT_H, bg, node));
    });
    // Connect sequential pairs with arrows
    for (let i = 0; i < rects.length - 1; i++) {
        const a = rects[i];
        const b = rects[i + 1];
        if (a !== undefined && b !== undefined) {
            elements.push(makeArrow(a.x + RECT_W, a.y + RECT_H / 2, b.x, b.y + RECT_H / 2));
        }
    }
    return elements;
}
function buildDataFlow(nodes) {
    const elements = [];
    const bg = COLOR['data-flow'];
    nodes.forEach((node, i) => {
        const x = i * (RECT_W + 60);
        const y = 80;
        elements.push(...makeRect(x, y, RECT_W, RECT_H, bg, node));
        if (i < nodes.length - 1) {
            elements.push(makeArrow(x + RECT_W, y + RECT_H / 2, x + RECT_W + 60, y + RECT_H / 2));
        }
    });
    return elements;
}
function buildSequence(nodes) {
    const elements = [];
    const bg = COLOR.sequence;
    const laneW = Math.max(120, RECT_W);
    const laneGap = laneW + 80;
    // Swimlane headers
    nodes.forEach((node, i) => {
        const x = i * laneGap;
        elements.push(...makeRect(x, 0, laneW, 50, bg, node));
        // Vertical line
        elements.push(makeArrow(x + laneW / 2, 50, x + laneW / 2, 50 + nodes.length * GAP_Y));
    });
    // Horizontal arrows between adjacent lanes
    for (let i = 0; i < nodes.length - 1; i++) {
        const y = 100 + i * 80;
        const x1 = i * laneGap + laneW;
        const x2 = (i + 1) * laneGap;
        elements.push(makeArrow(x1, y, x2, y));
    }
    return elements;
}
function buildEr(nodes) {
    const elements = [];
    const bg = COLOR.er;
    const dBg = '#d35400';
    nodes.forEach((node, i) => {
        const col = i % COLS;
        const row = Math.floor(i / COLS);
        const x = col * (GAP_X + 20);
        const y = row * (GAP_Y + 40);
        elements.push(...makeRect(x, y, RECT_W, RECT_H, bg, node));
        // Add relationship diamond between consecutive nodes in the same row
        if (i < nodes.length - 1 && (i + 1) % COLS !== 0) {
            const midX = x + RECT_W + 10;
            const midY = y;
            elements.push(...makeDiamond(midX, midY, 60, 40, dBg, 'has'));
        }
    });
    return elements;
}
function buildFlow(nodes) {
    const elements = [];
    const rectBg = COLOR.flow;
    const diamondBg = '#576574';
    let currentY = 0;
    nodes.forEach((node, i) => {
        const x = 80;
        const isDecision = i % 3 === 2;
        if (isDecision) {
            elements.push(...makeDiamond(x, currentY, RECT_W, 60, diamondBg, node));
            currentY += 60;
        }
        else {
            elements.push(...makeRect(x, currentY, RECT_W, RECT_H, rectBg, node));
            currentY += RECT_H;
        }
        if (i < nodes.length - 1) {
            elements.push(makeArrow(x + RECT_W / 2, currentY, x + RECT_W / 2, currentY + 30));
            currentY += 30;
        }
    });
    return elements;
}
/** Fallback builder for diagram types not supported by excalidraw (uses architecture layout). */
function buildGeneric(nodes) {
    return buildArchitecture(nodes);
}
// ---------------------------------------------------------------------------
// Public API
// ---------------------------------------------------------------------------
const BUILDERS = {
    architecture: buildArchitecture,
    'data-flow': buildDataFlow,
    sequence: buildSequence,
    er: buildEr,
    flow: buildFlow,
};
/** Generate an Excalidraw JSON diagram from a text description and diagram type. */
export function generateExcalidrawDiagram(description, diagramType) {
    const nodes = parseNodes(description);
    const builder = BUILDERS[diagramType] ?? buildGeneric;
    const elements = builder(nodes);
    return {
        type: 'excalidraw',
        version: 2,
        source: 'https://excalidraw.com',
        elements,
        appState: { viewBackgroundColor: '#ffffff', gridSize: null },
        files: {},
    };
}
/** Convert an Excalidraw diagram to a shareable excalidraw.com URL. */
export function toExcalidrawUrl(diagram) {
    const json = JSON.stringify(diagram);
    const encoded = Buffer.from(json).toString('base64');
    return `https://excalidraw.com/#json=${encoded}`;
}
//# sourceMappingURL=excalidraw-generator.js.map