const fs = require("fs");
const path = require("path");
const findUp = require("find-up");

const pkgDir = require("pkg-dir");

const isComponentLibraryEnv = __dirname.includes("node_modules");

const componentsBundlePolyfillPath = path.resolve(__dirname, "./cx-polyfills/componentsBundle.js");

/**
 * Devuelve la ruta completa del path común entre instancia-components y Griddo monorepo.
 * @param {string} customPath slug del path común entre instancia y monorepo del que se quiere obtener la ruta.
 * @returns {string | undefined} la ruta completa si el path existe o de lo contrario undefined.
 */
const resolveComponentsPath = (customPath = "") => {
	const filePath = isComponentLibraryEnv
		? path.resolve(pkgDir.sync(process.cwd()), customPath)
		: path.resolve(pkgDir.sync(__dirname), "../griddo-components", customPath);

	if (fs.existsSync(filePath)) {
		return filePath;
	}

	return undefined;
};

const resolveBuilderSSRPath = () => {
	const builderSSRPolyfillPath = path.resolve(__dirname, "./cx-polyfills/builder.ssr.js");
	const builderSSRPath = resolveComponentsPath("builder.ssr.js");
	const builderSSRPathExists = fs.existsSync(builderSSRPath);

	return builderSSRPathExists ? builderSSRPath : builderSSRPolyfillPath;
};

const getComponentsJSConfig = () => {
	const jsConfigPath = findUp.sync("jsconfig.json", { cwd: resolveComponentsPath() });
	const tsConfigPath = findUp.sync("tsconfig.json", { cwd: resolveComponentsPath() });

	return tsConfigPath || jsConfigPath || false;
};

/**
 * Devuelve la ruta completa de archivo de configuración de Griddo en la instancia: `griddo.config.js|ts`
 * @returns {string | undefined} la ruta completa del archivo de configuración
 */
const resolveComponentsGriddoConfig = () => {
	return resolveComponentsPath("griddo.config.js") || resolveComponentsPath("griddo.config.ts");
};

const getComponentsLibAliases = () => {
	const xsConfig = require(getComponentsJSConfig());

	return Object.keys(xsConfig?.compilerOptions?.paths).reduce(
		(currentAlias, pathKey) => {
			const [aliasKey] = pathKey.split("/");
			const [pathAtJsConfig] = xsConfig?.compilerOptions?.paths[pathKey];

			const [relativePathToDir] = pathAtJsConfig.split("/*");

			const absolutePath = resolveComponentsPath(relativePathToDir);

			return {
				...currentAlias,
				[aliasKey]: absolutePath,
			};
		},
		{
			components: componentsBundlePolyfillPath,
			__componentsIndex: resolveComponentsPath("src/index.js"),
			__componentsConfig: resolveComponentsGriddoConfig(),
			__ssrConfig: resolveBuilderSSRPath(),
			__ssrHelpers: path.resolve(__dirname, "./ssrHelpers"),
		},
	);
};

const griddoAxAliases = {
	"@ax/api": path.resolve(__dirname, "../../src/api/"),
	"@ax/components": path.resolve(__dirname, "../../src/components"),
	"@ax/containers": path.resolve(__dirname, "../../src/containers"),
	"@ax/forms": path.resolve(__dirname, "../../src/forms"),
	"@ax/guards": path.resolve(__dirname, "../../src/guards"),
	"@ax/helpers": path.resolve(__dirname, "../../src/helpers/"),
	"@ax/hooks": path.resolve(__dirname, "../../src/hooks/"),
	"@ax/modules": path.resolve(__dirname, "../../src/modules"),
	"@ax/routes": path.resolve(__dirname, "../../src/routes"),
	"@ax/types": path.resolve(__dirname, "../../src/types"),
	"@ax/schemas": path.resolve(__dirname, "../../src/schemas"),
	"@ax/locales": path.resolve(__dirname, "../../src/locales"),
	"@ax/constants": path.resolve(__dirname, "../../src/constants"),
};

const griddoComponentsLibAliases = getComponentsLibAliases();

const findCommonElements = (arr1, arr2) => arr1.some((item) => arr2.includes(item));

const thereAreAliasConflicts = () =>
	isComponentLibraryEnv && findCommonElements(Object.keys(griddoAxAliases), Object.keys(getComponentsLibAliases()));

const mergeComponentsAliases = (...arrs) => {
	const keys = arrs.map((arr) => Object.keys(arr)).flat();

	const merged = {};
	keys.map((key) => (merged[key] = [arrs.map((a) => a[key]).filter((a) => a !== undefined)].flat()));

	return merged;
};

/* Components Static Paths */
const componentsStaticPath = resolveComponentsPath("static");
const componentsStaticPathExists = fs.existsSync(componentsStaticPath);
const componentsThumbnailsPath = resolveComponentsPath("thumbnails");
const componentsThumbnailsPathExists = fs.existsSync(componentsThumbnailsPath);

module.exports = {
	isComponentLibraryEnv,
	componentsPath: resolveComponentsPath(),
	resolveComponentsPath,
	getComponentsJSConfig,
	getComponentsLibAliases,
	griddoComponentsLibAliases,
	griddoAxAliases,
	thereAreAliasConflicts,
	mergeComponentsAliases,
	projectAliases: { ...griddoAxAliases, ...griddoComponentsLibAliases },
	// projectAliases: mergeComponentsAliases(griddoComponentsLibAliases, griddoAxAliases),
	componentsStaticPath,
	componentsStaticPathExists,
	componentsThumbnailsPath,
	componentsThumbnailsPathExists,
	resolveComponentsGriddoConfig,
};
