/*
Copyright 2025 New Vector Ltd.

SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE files in the repository root for full details.
*/

import type { StorybookConfig } from "@storybook/react-vite";
import fs from "node:fs";
import { nodePolyfills } from "vite-plugin-node-polyfills";
import { mergeConfig, normalizePath, type Plugin } from "vite";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";

const __dirname = dirname(fileURLToPath(import.meta.url));
const srcRoot = normalizePath(join(__dirname, "..", "src"));
const sharedComponentsLayer = "shared-components";

// Get a list of available languages so the language selector can display them at runtime
const languageFiles = fs.readdirSync(join(__dirname, "..", "src", "i18n", "strings")).map((f) => f.slice(0, -5));

const languages: Record<string, string> = {};
for (const lang of languageFiles) {
    const normalizedLanguage = lang.toLowerCase().replace("_", "-");
    const languageParts = normalizedLanguage.split("-");
    if (languageParts.length === 2 && languageParts[0] === languageParts[1]) {
        languages[languageParts[0]] = `${lang}.json`;
    } else {
        languages[normalizedLanguage] = `${lang}.json`;
    }
}

/**
 * This function is used to resolve the absolute path of a package.
 * It is needed in projects that use Yarn PnP or are set up within a monorepo.
 */
function getAbsolutePath(value: string): any {
    return dirname(fileURLToPath(import.meta.resolve(`${value}/package.json`)));
}

function layerSharedComponentCssModules(): Plugin {
    return {
        name: "element-web-shared-components-storybook-css-layer",
        enforce: "pre",
        transform(code, id) {
            const cssPath = normalizePath(id.split("?")[0]);
            if (!cssPath.startsWith(srcRoot) || !cssPath.endsWith(".module.css")) {
                return;
            }

            return {
                code: `@layer ${sharedComponentsLayer} {\n${code}\n}\n`,
                map: null,
            };
        },
    };
}

const config: StorybookConfig = {
    stories: ["../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
    addons: [
        "@storybook/addon-docs",
        "@storybook/addon-designs",
        "@storybook/addon-a11y",
        "@storybook/addon-vitest",
        getAbsolutePath("storybook-addon-vis"),
    ],
    framework: "@storybook/react-vite",
    core: {
        disableTelemetry: true,
    },
    typescript: {
        reactDocgen: "react-docgen-typescript",
        reactDocgenTypescriptOptions: {
            // The default exclude is ["**/**.stories.tsx"] which prevents
            // docgen from extracting snapshot field descriptions from wrapper
            // components defined in story files.
            exclude: [],
        },
    },
    async viteFinal(config) {
        return mergeConfig(config, {
            plugins: [
                layerSharedComponentCssModules(),
                // Needed for counterpart to work
                nodePolyfills({ include: ["util"], globals: { global: false } }),
                {
                    name: "language-middleware",
                    configureServer(server) {
                        server.middlewares.use((req, res, next) => {
                            if (req.url === "/i18n/languages.json") {
                                // Dynamically generate a languages.json file based on what files are available
                                res.setHeader("Content-Type", "application/json");
                                res.end(JSON.stringify(languages));
                            } else if (req.url === "/usercontent/" || req.url === "/usercontent") {
                                // Mock usercontent endpoint used by encrypted download iframes.
                                res.end("This is where /usercontent/ is loaded.");
                            } else if (req.url?.startsWith("/i18n/")) {
                                // Serve the individual language files, which annoyingly can't be a simple
                                // static dir because the directory structure in src doesn't match what
                                // the app requests.
                                const langFile = req.url.split("/").pop();
                                res.setHeader("Content-Type", "application/json");
                                fs.createReadStream(`src/i18n/strings/${langFile}`).pipe(res);
                            } else {
                                next();
                            }
                        });
                    },
                },
            ],
            server: {
                allowedHosts: ["localhost", ".docker.internal"],
            },
        });
    },
    refs: {
        "compound-web": {
            title: "Compound Web",
            url: "https://element-hq.github.io/compound-web/",
        },
    },
    env: (config) => ({
        ...config,
        STORYBOOK_LANGUAGES: JSON.stringify(Object.keys(languages)),
    }),
};
export default config;
