import { Color } from './html/highlighter/properties/color.js';
import { Property } from './html/highlighter/property.js';
import { Span } from './html/highlighter/span.js';
import { Inspector } from './html/inspector.js';

const sameProperties = (a: Array<Property> | undefined, b: Array<Property> | undefined): boolean => {
    if (a === undefined || b === undefined) return false;
    if (a.length !== b.length) return false;

    for (const property of a) {
        let found = false;

        for (const otherProperty of b)
            if (property.equals(otherProperty))
                found = true;

        if (!found) return false;
    }

    return true;
};

const applyProperties = (element: HTMLSpanElement, properties: Array<Property>): void => {
    for (const property of properties)
        property.apply(element);
};

export function render(text: string, spans: Array<Span>, inspector: Inspector): void {
    console.time('render');

    const container = document.createElement('pre');
    container.ariaHidden = 'true';

    for (const child of document.body.children) {
        (child as HTMLElement).style.display = 'none';
        child.ariaHidden = 'false';
    }

    document.body.appendChild(container);

    const defaultProperties: Array<Property> = [ Color.Plain ];
    const defaultTagName: keyof HTMLElementTagNameMap = 'span';

    let lastProperties: Array<Property> = defaultProperties;
    let lastTagName: keyof HTMLElementTagNameMap = defaultTagName;
    let lastElement: HTMLSpanElement = document.createElement(lastTagName);

    applyProperties(lastElement, lastProperties);

    container.appendChild(lastElement);

    for (let characterIndex = 0; characterIndex < text.length; characterIndex++) {
        const character = text[characterIndex];

        let topMostProperties: Array<Property> = defaultProperties;
        let topMostTagName: keyof HTMLElementTagNameMap = defaultTagName;

        const matchingSpans = new Array<Span>();

        for (const span of spans) {
            if (span.contains(characterIndex)) {
                matchingSpans.push(span);

                topMostProperties = span.properties;
                topMostTagName = span.tagName;
            }
        }

        if (sameProperties(lastProperties, topMostProperties) && topMostTagName === lastTagName) {
            lastElement.textContent += character;

            inspector.instrument(lastElement, matchingSpans);
        } else {
            lastElement = document.createElement(topMostTagName);
            lastElement.textContent = character;

            inspector.instrument(lastElement, matchingSpans);

            applyProperties(lastElement, topMostProperties);

            lastProperties = topMostProperties;
            lastTagName = topMostTagName;

            container.appendChild(lastElement);
        }
    }

    console.timeEnd('render');
}
