const fs = require('fs');
const VueServerRenderer = require('vue-server-renderer');

if (process.stdin.isTTY) {
    throw new Error(`
        The render command is expected to receive the raw template to render via STDIN. Please pipe some content
        to this command like this:

        $ echo '<p>Some content to render here</p>' | node ssr-cli.js [...]
    `);
}

render(
    process.env.WRAPPER_ID,
    process.env.TOUBIZ_WIDGET_SSR_BUNDLE,
    process.env.TOUBIZ_WIDGET_SSR_CLIENT_MANIFEST,
)
    .then(rendered => process.stdout.write(rendered))
    .catch(error => {
        console.error(error);
        process.exit(1);
    });

async function render(id, serverBundle, clientManifestPath) {
    const tailwindConfig = require('%%TOUBIZ_WIDGET_TAILWIND_CONFIG%%');
    const clientManifest = JSON.parse(fs.readFileSync(clientManifestPath).toString());
    const template = `
        <div
            class="toubiz-widget-rendering toubiz-widget-rendering--ssr"
            id="toubiz-widget-rendering-${id}"
            data-toubiz-widget-rendering
            data-toubiz-widget-rendering.ssr="${id}"
        >
            <tb-component-library-wrapper>
                ${await readStdin()}
            </tb-component-library-wrapper>
        </div>
    `;

    return `
        ${await doServerSideRendering(serverBundle, clientManifest, template)}
        ${getLinkTagsForGeneratedCssFiles(clientManifest).join("\n")}
        <template data-toubiz-widget-rendering.template="${id}">
            ${template}
        </template>
        <style>
            #toubiz-widget-rendering-${id} {
                ${getCssCustomPropertyDefinitions(tailwindConfig).join("\n")}
            }
        </style>
    `;
}

function readStdin() {
    return new Promise(resolve => {
        let stdin = '';
        process.stdin.on('data', data => stdin += data);
        process.stdin.on('end', () => resolve(stdin));
    });
}

function getCssCustomPropertyDefinitions(tailwindConfig) {
    const lines = [];

    for (const [ colorName, shades ] of Object.entries(tailwindConfig.theme.colors)) {
        if (typeof shades !== 'object') {
            continue;
        }

        for (const [ shade, colorHex ] of Object.entries(shades)) {
            lines.push(`--tb-color-${colorName}-${shade}: ${colorHex};`);
        }
    }
    return lines;
}

function doServerSideRendering(serverBundle, clientManifest, template) {
    const renderer = VueServerRenderer.createBundleRenderer(serverBundle, {
        runInNewContext: true,
        clientManifest,
    });

    const context = { template };
    return renderer.renderToString(context).then(html => `
        ${html}
        ${context.renderStyles()}
        ${context.renderScripts()}
    `);
}

function getLinkTagsForGeneratedCssFiles(clientManifest)
{
    const publicPath = clientManifest.publicPath;
    return clientManifest.all
        .filter(path => path.match(/\.css(\?\w+)?$/))
        .map(path => `<link rel="stylesheet" href="${publicPath}/${path}">`);
}
