/**
 * portalFactories — реестр 3D-арок порталов GD (смена гейммода).
 *
 * 6 гейммодов × 5 вариантов = 30 арок. Каждая арка:
 *   - 2 вертикальные колонны (по бокам проёма ~3м)
 *   - 1 горизонтальная балка сверху
 *   - табличка с символом/названием гейммода (CUBE / SHIP / BALL / UFO / WAVE / ROBOT)
 *   - неоновая подсветка в цвете режима
 *
 * Возвращает (scene, id) => { root: TransformNode, dispose() }.
 * Габариты: ширина проёма ~3м, высота ~4м, центр в (0, 0, 0).
 * Низ колонн на y=0; ставить корнем на y=1 (на верх пола, как GdStartArch).
 */
import {
    MeshBuilder, StandardMaterial, Color3, Vector3, TransformNode,
    DynamicTexture,
} from '@babylonjs/core';

// =========================================================================
// УТИЛИТЫ
// =========================================================================

function makeMat(scene, name, opts = {}) {
    const m = new StandardMaterial(name, scene);
    m.diffuseColor = new Color3(...(opts.diffuse || [1, 1, 1]));
    m.emissiveColor = new Color3(...(opts.emissive || [0, 0, 0]));
    m.specularColor = new Color3(...(opts.specular || [0.2, 0.2, 0.2]));
    if (opts.specPower != null) m.specularPower = opts.specPower;
    if (opts.alpha != null) m.alpha = opts.alpha;
    if (opts.disableLighting) m.disableLighting = true;
    return m;
}

function makeColumn(scene, name, opts = {}) {
    const {
        height = 3.6, diameter = 0.5, shape = 'cylinder',
        diffuse, emissive, specular, specPower,
    } = opts;
    let mesh;
    if (shape === 'box') {
        mesh = MeshBuilder.CreateBox(name, { width: diameter, height, depth: diameter }, scene);
    } else if (shape === 'oct') {
        mesh = MeshBuilder.CreateCylinder(name, { diameter, height, tessellation: 8 }, scene);
    } else {
        mesh = MeshBuilder.CreateCylinder(name, { diameter, height, tessellation: 16 }, scene);
    }
    mesh.position.y = height / 2;
    mesh.material = makeMat(scene, `${name}_mat`, { diffuse, emissive, specular, specPower });
    return mesh;
}

function makeBeam(scene, name, opts = {}) {
    const {
        width = 3.5, height = 0.5, depth = 0.5,
        diffuse, emissive, specular, specPower,
    } = opts;
    const beam = MeshBuilder.CreateBox(name, { width, height, depth }, scene);
    beam.material = makeMat(scene, `${name}_mat`, { diffuse, emissive, specular, specPower });
    return beam;
}

/** Табличка с текстом-символом гейммода. */
function makeSignText(scene, name, text, opts = {}) {
    const {
        width = 2.4, height = 0.7,
        bgColor = '#0a1428', textColor = '#ffffff',
        fontSize = 88, fontFamily = 'sans-serif',
        emissive = [0.6, 0.6, 0.6],
    } = opts;
    const TW = 512, TH = 128;
    const dt = new DynamicTexture(`${name}_tex`, { width: TW, height: TH }, scene, true);
    const ctx = dt.getContext();
    ctx.fillStyle = bgColor;
    ctx.fillRect(0, 0, TW, TH);
    ctx.fillStyle = textColor;
    ctx.font = `bold ${fontSize}px ${fontFamily}`;
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.fillText(text, TW / 2, TH / 2);
    dt.hasAlpha = false;
    dt.update();
    const plane = MeshBuilder.CreatePlane(name, { width, height }, scene);
    const mat = new StandardMaterial(`${name}_mat`, scene);
    mat.diffuseTexture = dt;
    mat.emissiveTexture = dt;
    mat.emissiveColor = new Color3(...emissive);
    mat.disableLighting = true;
    mat.backFaceCulling = false;
    plane.material = mat;
    return plane;
}

/** Неоновая лента вокруг проёма (P-образно). */
function makeNeonOutline(scene, idBase, gap, colH, color) {
    const meshes = [];
    const tube = (name, w, h, x, y) => {
        const m = MeshBuilder.CreateBox(name, { width: w, height: h, depth: 0.12 }, scene);
        m.position.set(x, y, 0.22);
        m.material = makeMat(scene, `${name}_mat`, {
            diffuse: color, emissive: color, disableLighting: true,
        });
        meshes.push(m);
        return m;
    };
    // Левая лента, правая лента, верхняя
    tube(`${idBase}_neonL`, 0.12, colH, -gap/2, colH/2);
    tube(`${idBase}_neonR`, 0.12, colH, gap/2, colH/2);
    tube(`${idBase}_neonT`, gap + 0.12, 0.12, 0, colH);
    return meshes;
}

/** Сферическая «лампочка»-glow. */
function makeBulb(scene, name, x, y, z, color, scale = 1) {
    const bulb = MeshBuilder.CreateSphere(name, { diameter: 0.20, segments: 8 }, scene);
    bulb.position.set(x, y, z);
    bulb.scaling.set(scale, scale, scale);
    bulb.material = makeMat(scene, `${name}_mat`, {
        diffuse: color, emissive: color, disableLighting: true,
    });
    return bulb;
}

/** Финиш-стиль: 2 колонны + балка + табличка. Это база для всех вариантов. */
function buildArch(scene, id, opts) {
    const root = new TransformNode(`portal_arch_${id}`, scene);
    const {
        colShape = 'cylinder',
        colDiameter = 0.55,
        colH = 3.6,
        gap = 3.0,
        beamH = 0.45,
        frameDif, frameEm,
        signText = 'PORTAL',
        signColor = '#ffffff',
        signBg = '#0a1428',
        accent,        // цвет неона/glow
        extras,        // function(scene, id, root, gap, colH) — доп. декор
        addNeon = false,
        addBulbs = false,
    } = opts;

    const colL = makeColumn(scene, `${id}_colL`, {
        height: colH, diameter: colDiameter, shape: colShape,
        diffuse: frameDif, emissive: frameEm,
        specular: [0.5, 0.5, 0.5], specPower: 64,
    });
    const colR = makeColumn(scene, `${id}_colR`, {
        height: colH, diameter: colDiameter, shape: colShape,
        diffuse: frameDif, emissive: frameEm,
        specular: [0.5, 0.5, 0.5], specPower: 64,
    });
    colL.position.x = -gap/2;
    colR.position.x = gap/2;
    colL.parent = root; colR.parent = root;

    const beam = makeBeam(scene, `${id}_beam`, {
        width: gap + colDiameter + 0.2, height: beamH, depth: 0.5,
        diffuse: frameDif, emissive: frameEm,
        specular: [0.5, 0.5, 0.5], specPower: 64,
    });
    beam.position.y = colH + beamH/2;
    beam.parent = root;

    const sign = makeSignText(scene, `${id}_sign`, signText, {
        width: 2.3, height: 0.7, textColor: signColor, bgColor: signBg,
        emissive: hexToRgb01(accent || signColor),
    });
    sign.position.set(0, colH - 0.2, 0.28);
    sign.parent = root;

    if (addNeon && accent) {
        const ns = makeNeonOutline(scene, id, gap, colH, hexToRgb01(accent));
        for (const m of ns) m.parent = root;
    }
    if (addBulbs && accent) {
        // 6 лампочек по балке
        const c = hexToRgb01(accent);
        for (let i = 0; i < 6; i++) {
            const bx = -gap/2 + (i * gap / 5);
            const b = makeBulb(scene, `${id}_bulb_${i}`, bx, colH + beamH + 0.18, 0.0, c, 1.0);
            b.parent = root;
        }
    }
    if (extras) {
        try { extras(scene, id, root, gap, colH); } catch (e) {}
    }

    return {
        root,
        dispose: () => {
            for (const ch of root.getChildMeshes()) ch.dispose();
            root.dispose();
        },
    };
}

function hexToRgb01(hex) {
    if (Array.isArray(hex)) return hex;
    const h = hex.replace('#', '');
    return [
        parseInt(h.slice(0, 2), 16) / 255,
        parseInt(h.slice(2, 4), 16) / 255,
        parseInt(h.slice(4, 6), 16) / 255,
    ];
}

// =========================================================================
// ФАБРИКИ — 6 гейммодов × 5 вариантов
// =========================================================================

// Цвета режимов (rgb 0..1 для эмиссии и hex для текстов)
const COLORS = {
    cube:  { hex: '#22ff66', rgb: [0.13, 1.00, 0.40] },   // зелёный
    ship:  { hex: '#ff44aa', rgb: [1.00, 0.27, 0.67] },   // розовый
    ball:  { hex: '#ff8833', rgb: [1.00, 0.53, 0.20] },   // оранжевый
    ufo:   { hex: '#ffe44a', rgb: [1.00, 0.89, 0.29] },   // жёлтый
    wave:  { hex: '#33aaff', rgb: [0.20, 0.67, 1.00] },   // голубой
    robot: { hex: '#bbbbbb', rgb: [0.73, 0.73, 0.73] },   // серый
};
const LABELS = {
    cube: 'CUBE', ship: 'SHIP', ball: 'BALL',
    ufo: 'UFO',   wave: 'WAVE', robot: 'ROBOT',
};

// Helper для group-фабрики: возвращает фабрику с правильными цветами
function archForGroup(group, variant, opts) {
    return (scene, id) => buildArch(scene, id, {
        ...opts,
        signText: LABELS[group],
        signColor: COLORS[group].hex,
        accent: COLORS[group].hex,
    });
}

// 5 вариантов формы (повторяются для всех групп):
const VARIANTS = {
    // v1 — Классический: толстые цилиндрические колонны, чистый рамка
    v1: (group) => archForGroup(group, 1, {
        colShape: 'cylinder', colDiameter: 0.55, colH: 3.6, gap: 3.0, beamH: 0.45,
        frameDif: [0.30, 0.30, 0.32], frameEm: [0.05, 0.05, 0.06],
        signBg: '#0a1428',
    }),
    // v2 — Круглый: тонкие колонны + декоративные кольца + неоновая обводка
    v2: (group) => archForGroup(group, 2, {
        colShape: 'cylinder', colDiameter: 0.40, colH: 3.6, gap: 3.0, beamH: 0.35,
        frameDif: [0.18, 0.18, 0.22], frameEm: [0.08, 0.08, 0.10],
        addNeon: true,
        signBg: '#000000',
        extras: (scene, id, root, gap, colH) => {
            // Кольца на колоннах
            const c = COLORS[group === 'cube' ? 'cube' : group].rgb;
            for (let side of [-1, 1]) {
                for (let i = 0; i < 3; i++) {
                    const r = MeshBuilder.CreateTorus(`${id}_ring_${side}_${i}`,
                        { diameter: 0.65, thickness: 0.06, tessellation: 16 }, scene);
                    r.position.set(side * gap/2, 0.8 + i * 1.0, 0);
                    r.rotation.x = Math.PI / 2;
                    r.material = makeMat(scene, `${id}_ring_mat_${side}_${i}`, {
                        diffuse: c, emissive: c, disableLighting: true,
                    });
                    r.parent = root;
                }
            }
        },
    }),
    // v3 — Высокий: квадратные колонны (box), массивная балка
    v3: (group) => archForGroup(group, 3, {
        colShape: 'box', colDiameter: 0.70, colH: 4.2, gap: 3.2, beamH: 0.6,
        frameDif: [0.45, 0.45, 0.48], frameEm: [0.12, 0.12, 0.14],
        addBulbs: true,
        signBg: '#1a1a2e',
    }),
    // v4 — Неон тонкий: очень тонкие колонны (только неон-обводка читается)
    v4: (group) => archForGroup(group, 4, {
        colShape: 'cylinder', colDiameter: 0.25, colH: 3.5, gap: 3.0, beamH: 0.20,
        frameDif: [0.10, 0.10, 0.14], frameEm: [0.05, 0.05, 0.08],
        addNeon: true,
        signBg: '#050510',
    }),
    // v5 — Восьмигранный: oct-колонны + лампочки
    v5: (group) => archForGroup(group, 5, {
        colShape: 'oct', colDiameter: 0.65, colH: 3.8, gap: 3.1, beamH: 0.50,
        frameDif: [0.35, 0.30, 0.40], frameEm: [0.10, 0.08, 0.12],
        addBulbs: true,
        addNeon: false,
        signBg: '#0e0a14',
    }),
};

// =========================================================================
// КАТАЛОГ
// =========================================================================
export const PORTAL_CATALOG = [];

function add(group, num, title, make) {
    PORTAL_CATALOG.push({
        id: `${group}_v${num}`,
        group,
        title,
        make,
    });
}

const VARIANT_TITLES = {
    1: 'Классическая',
    2: 'Кольца + неон',
    3: 'Массивная',
    4: 'Неон тонкий',
    5: 'Восьмигранная',
};

for (const group of ['cube', 'ship', 'ball', 'ufo', 'wave', 'robot']) {
    for (const num of [1, 2, 3, 4, 5]) {
        const factory = VARIANTS[`v${num}`](group);
        add(group, num, VARIANT_TITLES[num], factory);
    }
}

export const PORTAL_GROUPS = [
    { id: 'cube',  name: 'Cube — Куб',         emoji: '🟦', color: '#22ff66' },
    { id: 'ship',  name: 'Ship — Корабль',     emoji: '🚀', color: '#ff44aa' },
    { id: 'ball',  name: 'Ball — Шар',         emoji: '🟢', color: '#ff8833' },
    { id: 'ufo',   name: 'UFO — НЛО',          emoji: '🛸', color: '#ffe44a' },
    { id: 'wave',  name: 'Wave — Волна',       emoji: '〰', color: '#33aaff' },
    { id: 'robot', name: 'Robot — Робот',      emoji: '🤖', color: '#bbbbbb' },
];

export function getPortalsByGroup(group) {
    return PORTAL_CATALOG.filter(p => p.group === group);
}
