import { sortBy } from "@ax/helpers";
import { pageSchemas } from "@ax/schemas";
import type { ISchema, ModuleCategoryInfo } from "@ax/types";

import { config } from "components";

const schemas = config.schemas.ui;
const schemasConfig = config.schemas.config;
const formSchemas = config.schemas.forms;
const contentTypesSchemas = config.schemas.contentTypes;
const moduleCategories = config.schemas.config.moduleCategories;
const allSchemas = {
	...schemas.modules,
	...schemas.components,
	...formSchemas?.fields,
	...pageSchemas,
};

const getSchema = (name: string): ISchema | undefined => allSchemas[name];

const getDefaultSchema = (name: string) => {
	const defaultSchema = allSchemas[name] ? allSchemas[name].default : {};

	for (const key of Object.keys(defaultSchema)) {
		if (
			defaultSchema[key] &&
			typeof defaultSchema[key] === "object" &&
			Object.prototype.hasOwnProperty.call(defaultSchema[key], "schema")
		) {
			defaultSchema[key] = getDefaultSchema(defaultSchema[key].schema);
		}
		if (Array.isArray(defaultSchema[key])) {
			for (const i in defaultSchema[key]) {
				if (
					defaultSchema[key][i] &&
					typeof defaultSchema[key][i] === "object" &&
					Object.prototype.hasOwnProperty.call(defaultSchema[key][i], "schema")
				) {
					defaultSchema[key][i] = getDefaultSchema(defaultSchema[key][i].schema);
				}
			}
		}
	}

	return defaultSchema;
};

const getSchemaThumbnails = (name: string, theme?: string) => {
	if (!allSchemas[name]?.thumbnails) return null;

	return theme && allSchemas[name].thumbnails[theme] ? allSchemas[name].thumbnails[theme] : allSchemas[name].thumbnails;
};

const getTemplate = (name: string) => {
	return schemas.templates[name];
};

const getDefaultTemplate = (name: string) => {
	return schemas.templates[name].default;
};

const getFormTemplates = (): Record<string, ISchema> => {
	return formSchemas?.templates || {};
};

const getFormTemplate = (name: string): ISchema | undefined => {
	return formSchemas?.templates[name];
};

const getDefaultFormTemplate = (name: string): Record<string, any> | undefined => {
	return formSchemas?.templates[name]?.default;
};

const getSchemaFormCategories = (): { label: string; value: string; featured?: boolean }[] => {
	return formSchemas?.categories || [];
};

const getFormTemplateCategories = (): { label: string; value: string }[] => {
	return formSchemas?.templateCategories || [];
};

const getTemplateThumbnails = (name: string, theme?: string) => {
	if (!schemas.templates[name]?.thumbnails) {
		return null;
	}

	return theme && schemas.templates[name].thumbnails[theme]
		? schemas.templates[name].thumbnails[theme]
		: schemas.templates[name]?.thumbnails;
};

const getFormTemplateThumbnails = (name: string): Record<string, string> | null => {
	return formSchemas?.templates[name]?.thumbnails ? formSchemas?.templates[name].thumbnails : null;
};

const getDataPackSchema = (name: string) => {
	return contentTypesSchemas.dataPacks[name];
};

const getDisplayName = (component: string): string => {
	const schema = getSchema(component);
	return schema?.displayName || "";
};

const getSchemaType = (component: string) => {
	const { schemaType } = getSchema(component) || {};
	return schemaType;
};

const getTemplateType = (template: string) => {
	const { type } = getTemplate(template);
	return type;
};

const getTemplateDisplayName = (template: string) => {
	const schema = getTemplate(template);
	return schema ? schema.displayName : undefined;
};

const getMenuItems = (type: string): { fields: any[] } | undefined => {
	return schemasConfig.menuItems[type];
};

const filterByCategory = (options: any, category: string) => {
	return options.filter((option: any) => allSchemas[option]?.category === category);
};

const getModuleCategories = (moduleList: string[]): ModuleCategoryInfo[] => {
	const categories: string[] = [];

	const allCategory: ModuleCategoryInfo = {
		label: "All",
		value: "all",
		featured: true,
	};

	moduleList.forEach((module) => {
		const categoryValue = getSchema(module)?.category;
		if (categoryValue) {
			const foundCategory = moduleCategories.find((category: ModuleCategoryInfo) => category.value === categoryValue);

			if (foundCategory) {
				categories.push(foundCategory);
			}
		}
	});

	const uniqueCategories: ModuleCategoryInfo[] = categories
		.reduce((acc: any, current: any) => {
			const item = acc.find((item: any) => item.value === current.value);
			return item ? acc : acc.concat([current]);
		}, [])
		.sort(sortBy("label", false));

	return uniqueCategories.length > 0 ? [allCategory, ...uniqueCategories] : [];
};

const getModuleStyles = (module: string): any[] => {
	const styles = getSchema(module)?.styles;
	const options: any[] = [];
	styles &&
		Object.keys(styles).forEach((key: string) => {
			options.push({ value: key, img: styles[key] });
		});
	return options;
};

const getNavigationModules = (): Record<string, any[]> => {
	const navigationModules: Record<string, any[]> = { header: [], footer: [] };
	Object.keys(schemas.modules).forEach((key: string) => {
		const moduleType = schemas.modules[key].type;
		if (["header", "footer"].includes(moduleType)) {
			navigationModules[moduleType].push(schemas.modules[key]);
		}
	});
	return navigationModules;
};

const getDefaultNavigationModules = (): Record<string, any> => {
	const navigationModules: Record<string, any[]> = getNavigationModules();
	const defaultHeader = navigationModules.header.find((header: any) => header.defaultNavigation);
	const defaultFooter = navigationModules.footer.find((footer: any) => footer.defaultNavigation);
	return {
		defaultHeader: defaultHeader || navigationModules.header[0],
		defaultFooter: defaultFooter || navigationModules.footer[0],
	};
};

const isMultipleNavigationModules = (): boolean => {
	const navigationModules: Record<string, any[]> = getNavigationModules();
	return navigationModules.header.length > 1 || navigationModules.footer.length > 1;
};

export {
	getSchema,
	getDefaultSchema,
	getTemplate,
	getDefaultTemplate,
	getDisplayName,
	getSchemaThumbnails,
	getTemplateThumbnails,
	getSchemaType,
	getTemplateType,
	getTemplateDisplayName,
	getMenuItems,
	filterByCategory,
	getModuleCategories,
	getModuleStyles,
	getDataPackSchema,
	getNavigationModules,
	getDefaultNavigationModules,
	isMultipleNavigationModules,
	getFormTemplate,
	getDefaultFormTemplate,
	getFormTemplates,
	getFormTemplateThumbnails,
	getSchemaFormCategories,
	getFormTemplateCategories,
};
