
import { Lazy, resolve_lazy } from './lazy';

const attrs_pattern = /\s+\{\s*(?:[\.#:][^\s]+(?:\s*[\.#:][^\s]+)*)?\s*}$/;

export interface ParsedAttributes {
	id?: string;
	classes: string[];
	attrs: Record<string, string | string[]>;
	html_attrs: string[];
	text: string;
}

export function parse_attributes(text: string, fallback_id?: Lazy<string>) {
	const attrs: ParsedAttributes = {
		id: null,
		classes: [ ],
		attrs: { },
		html_attrs: [ ],
		text,
	};

	const attrs_match = attrs_pattern.exec(text);

	if (attrs_match) {
		attrs.text = text.slice(0, -attrs_match[0].length).trim();

		const raw_attrs = attrs_match[0].trim().slice(1, -1).trim().split(/\s+/g);

		for (const attr of raw_attrs) {
			if (attr.startsWith('.')) {
				attrs.classes.push(attr.slice(1));
			}

			else if (attr.startsWith('#')) {
				attrs.id = attr.slice(1);
			}

			else if (attr.startsWith(':')) {
				const eq_index = attr.indexOf('=');

				if (eq_index === -1) {
					const name = attr.slice(1);
					attrs.attrs[name] = '';
				}

				const name = attr.slice(1, eq_index);
				const value = attr.slice(eq_index + 1);

				// Enable passing the same attribute more than once for lists, i.e.:
				//   {:rel=external :rel=nofollow}
				// should render as:
				//   rel="external nofollow"
				if (attrs.attrs[name]) {
					if (! Array.isArray(attrs.attrs[name])) {
						attrs.attrs[name] = [ attrs.attrs[name] as string ];
					}

					(attrs.attrs[name] as string[]).push(value);
				}

				else {
					attrs.attrs[name] = value;
				}
			}
		}
	}

	if (! attrs.id) {
		attrs.id = resolve_lazy(fallback_id);
	}

	if (attrs.id) {
		attrs.html_attrs.push(`id="${attrs.id}"`);
	}

	if (attrs.classes.length) {
		attrs.html_attrs.push(`class="${attrs.classes.join(' ')}"`);
	}

	for (const [name, value] of Object.entries(attrs.attrs)) {
		if (Array.isArray(value)) {
			attrs.html_attrs.push(`${name}="${value.join(' ')}"`);
		}

		else {
			attrs.html_attrs.push(value ? `${name}="${value}"` : name);
		}
	}

	return attrs;
}
