import { IS_BROWSER } from 'fresh/runtime'
import { styles } from './SmartStylesheetCommon.tsx'

/**
 * Generate a css scope for the given component/island based on its name.
 *
 * @param component - Component or island to scope.
 * @returns scope - css scope class.
 *
 * @example
 * ```ts
 * // ./(components|islands)/Button.tsx
 * import type { JSX } from 'preact'
 * import { getStyleScope, useSmartStylesheet } from './SmartStylesheet.tsx'
 *
 * const scope = getStyleScope(Button)
 *
 * export function Button(props: JSX.ButtonHTMLAttributes) {
 *   useSmartStylesheet(import.meta, { scope })
 *
 *   return <button class={scope} {...props} />
 * }
 * ```
 */
export function getStyleScope<T extends { name: Readonly<string> }>(
	component: T,
): string {
	// generate scope/class hash
	return `_scope_${
		btoa(component.name).slice(-10).replaceAll('=', '_').toLowerCase()
	}`
}

/**
 * Hook to load component/island stylesheet only when
 * it is imported by the served route.
 * For any `./(component|islands)/Element.tsx` it will
 * load the corresponding `./(component|islands)/Element.css`
 *
 * @param meta - Component ImportMeta used to resolve
 * stylesheet path, name and layer.
 * @param options - CSS scope to use (default: none)
 * and css layer ('components' or 'islands') depending of the ImportMeta.
 *
 * @example Basic usage
 * ```ts
 * // ./(components|islands)/Button.tsx
 * import type { JSX } from 'preact'
 * import { useSmartStylesheet } from './SmartStylesheet.tsx'
 *
 * export function Button(props: JSX.ButtonHTMLAttributes) {
 *   useSmartStylesheet(import.meta)
 *
 *   return <button class={scope} {...props} />
 * }
 * ```
 *
 * @example Use css scope
 * ```ts
 * // ./(components|islands)/Button.tsx
 * import type { JSX } from 'preact'
 * import { getStyleScope, useSmartStylesheet } from './SmartStylesheet.tsx'
 *
 * const scope = getStyleScope(Button)
 *
 * export function Button(props: JSX.ButtonHTMLAttributes) {
 *   useSmartStylesheet(import.meta, { scope })
 *
 *   return <button class={scope} {...props} />
 * }
 * ```
 *
 * @example Use custom layer
 * ```ts
 * // ./(components|islands)/Button.tsx
 * import type { JSX } from 'preact'
 * import { getStyleScope, useSmartStylesheet } from './SmartStylesheet.tsx'
 *
 * const scope = getStyleScope(Button)
 *
 * export function Button(props: JSX.ButtonHTMLAttributes) {
 *   useSmartStylesheet(import.meta, { scope, layer: 'custom' })
 *
 *   return <button class={scope} {...props} />
 * }
 * ```
 */
export function useSmartStylesheet(
	meta: ImportMeta,
	options?: { scope?: string; layer?: string },
) {
	if (IS_BROWSER) return

	// resolve filename
	const css = meta.filename
		?.replace('.tsx', '.css')
		.replace(Deno.cwd(), '')
		.replaceAll('\\', '/')

	if (!css) return
	if (styles.has(css)) return

	// set css layer
	const layerValue = options?.layer ?? css.includes('/components/')
		? 'components'
		: css.includes('/islands/')
		? 'islands'
		: undefined

	styles.set(css, { url: css, scope: options?.scope, layer: layerValue })
}
