/**
 * These triple-slash directives defines dependencies to various declaration files that will be
 * loaded when a user imports the StudioCMS plugin in their Astro configuration file. These
 * directives must be first at the top of the file and can only be preceded by this comment.
 */
/// <reference types="./virtual.d.ts" preserve="true" />
/// <reference types="studiocms/v/types" />

import { addVirtualImports } from '@withstudiocms/internal_helpers/astro-integration';
import type { AstroIntegration } from 'astro';
import { definePlugin } from 'studiocms/plugins';
import type { StudioCMSPluginDef } from 'studiocms/schemas';
import { shared } from './lib/shared.js';
import type { MDXPluginOptions } from './types.js';

function resolve(path: string) {
	return new URL(path, import.meta.url).toString();
}

/**
 * Creates an internal Astro integration for MDX functionality.
 * This is used by the StudioCMS plugin and can be used directly in tests.
 *
 * @param {string} packageIdentifier - The package identifier for the integration.
 * @param {MDXPluginOptions} [options] - Optional configuration options for the MDX plugin.
 * @returns {AstroIntegration} The configured Astro integration.
 */
export function internalMDXIntegration(
	packageIdentifier: string,
	options?: MDXPluginOptions
): AstroIntegration {
	// Resolve the path to the internal renderer
	const internalRenderer = resolve('./lib/render.js');

	// Resolve the options and set defaults if not provided
	const resolvedOptions = {
		remarkPlugins: options?.remarkPlugins || [],
		rehypePlugins: options?.rehypePlugins || [],
		recmaPlugins: options?.recmaPlugins || [],
		remarkRehypeOptions: options?.remarkRehypeOptions || {},
	};

	return {
		name: packageIdentifier,
		hooks: {
			'astro:config:setup': (params) => {
				// Add the virtual imports for the MDX renderer
				addVirtualImports(params, {
					name: packageIdentifier,
					imports: {
						'studiocms:mdx/renderer': `
							import { renderMDX as _render } from '${internalRenderer}';

							export const renderMDX = _render;
							export default renderMDX;
						`,
					},
				});
			},
			'astro:config:done': () => {
				// Store the resolved options in the shared context for the renderer
				shared.mdxConfig = resolvedOptions;
			},
		},
	};
}

/**
 * Creates and configures the StudioCMS MDX plugin.
 *
 * @param {MDXPluginOptions} [options] - Optional configuration options for the MDX plugin.
 * @returns {StudioCMSPluginDef} The configured StudioCMS plugin.
 *
 * @example
 * ```typescript
 * plugins: [
 *   studiocmsMDX({
 *     remarkPlugins: [],
 *     rehypePlugins: [],
 *     recmaPlugins: [],
 *     remarkRehypeOptions: {}
 *   }),
 * ]
 * ```
 */
export function studiocmsMDX(options?: MDXPluginOptions): StudioCMSPluginDef {
	// Define the package identifier
	const packageIdentifier = '@studiocms/mdx';

	// Resolve the path to the MDX renderer component
	const renderer = resolve('./components/render.js');

	const editor = resolve('./components/editor.astro');

	// Resolve the options and set defaults if not provided
	const resolvedOptions = {
		remarkPlugins: options?.remarkPlugins || [],
		rehypePlugins: options?.rehypePlugins || [],
		recmaPlugins: options?.recmaPlugins || [],
		remarkRehypeOptions: options?.remarkRehypeOptions || {},
	};

	// Return the plugin configuration
	return definePlugin({
		identifier: packageIdentifier,
		name: 'StudioCMS MDX',
		requires: ['@studiocms/md'],
		hooks: {
			'studiocms:astro-config': async ({ addIntegrations }) => {
				addIntegrations(internalMDXIntegration(packageIdentifier, resolvedOptions));
			},
			'studiocms:rendering': async ({ setRendering }) => {
				setRendering({
					pageTypes: [
						// Define the MDX page type
						{
							identifier: 'studiocms/mdx',
							label: 'MDX',
							pageContentComponent: editor,
							rendererComponent: renderer,
						},
					],
				});
			},
		},
	});
}

export default studiocmsMDX;
