---
import type {
	BuiltinLanguage,
	BuiltinTheme,
	LanguageRegistration,
	SpecialLanguage,
	ThemeRegistration,
	ThemeRegistrationRaw,
} from 'shikiji';
import { bundledLanguages } from 'shikiji/langs';
import { getCachedHighlighter } from '../dist/core/shiki.js';

interface Props {
	/** The code to highlight. Required. */
	code: string;
	/**
	 * The language of your code.
	 * Supports all languages listed here: https://github.com/shikijs/shiki/blob/main/docs/languages.md#all-languages
	 * Instructions for loading a custom language: https://github.com/shikijs/shiki/blob/main/docs/languages.md#supporting-your-own-languages-with-shiki
	 *
	 * @default "plaintext"
	 */
	lang?: BuiltinLanguage | SpecialLanguage | LanguageRegistration;
	/**
	 * The styling theme.
	 * Supports all themes listed here: https://github.com/shikijs/shiki/blob/main/docs/themes.md#all-themes
	 * Instructions for loading a custom theme: https://github.com/shikijs/shiki/blob/main/docs/themes.md#loading-theme
	 *
	 * @default "github-dark"
	 */
	theme?: BuiltinTheme | ThemeRegistration | ThemeRegistrationRaw;
	/**
	 * Multiple themes to style with -- alternative to "theme" option.
	 * Supports all themes found above; see https://github.com/antfu/shikiji#lightdark-dual-themes for more information.
	 */
	experimentalThemes?: Record<string, BuiltinTheme | ThemeRegistration | ThemeRegistrationRaw>;
	/**
	 * Enable word wrapping.
	 *  - true: enabled.
	 *  - false: disabled.
	 *  - null: All overflow styling removed. Code will overflow the element by default.
	 *
	 * @default false
	 */
	wrap?: boolean | null;
	/**
	 * Generate inline code element only, without the pre element wrapper.
	 *
	 * @default false
	 */
	inline?: boolean;
}

const {
	code,
	lang = 'plaintext',
	theme = 'github-dark',
	experimentalThemes = {},
	wrap = false,
	inline = false,
} = Astro.props;

// shiki -> shikiji compat
if (typeof lang === 'object') {
	// `id` renamed to `name` (always override)
	if ((lang as any).id) {
		lang.name = (lang as any).id;
	}
	// `grammar` flattened to lang itself
	if ((lang as any).grammar) {
		Object.assign(lang, (lang as any).grammar);
	}
}

const highlighter = await getCachedHighlighter({
	langs: [
		typeof lang === 'string'
			? Object.keys(bundledLanguages).includes(lang)
				? lang
				: 'plaintext'
			: lang,
	],
	theme,
	experimentalThemes,
	wrap,
});

const html = highlighter.highlight(code, typeof lang === 'string' ? lang : lang.name, {
	inline,
});
---

<Fragment set:html={html} />
