import { VERIFY } from '../../util/assertions.js';
import { Inspectable } from '../highlighter/inspectable.js';
import { Position } from './position.js';
import { Range } from './range.js';
import { REPLACEMENT_CHARACTER } from './token.js';

export class Attribute extends Inspectable {
    public name: string;
    public value: string;
    public nameRange!: Range;
    public valueRange?: Range;
    public equalsPosition?: Position;
    public quoted: boolean;

    public constructor(name: string, value: string) {
        super();

        this.name = name;
        this.value = value;
        this.quoted = true;

        // @ts-expect-error
        this.nameRange = {};
    }

    public setUnquoted(): void {
        this.quoted = false;
    }

    public appendToName(characters: string): void {
        this.name += characters;
    }

    public appendReplacementCharacterToName(): void {
        this.appendToName(REPLACEMENT_CHARACTER);
    }

    public appendToValue(characters: string): void {
        this.value += characters;
    }

    public appendReplacementCharacterToValue(): void {
        this.appendToValue(REPLACEMENT_CHARACTER);
    }

    public startingNameAt(position: Position): this {
        this.nameRange.start = position.copy();

        return this;
    }

    public endingNameAt(position: Position): this {
        this.nameRange.end = position.copy();

        return this;
    }

    public equalsAt(position: Position): this {
        this.equalsPosition = position.copy();

        return this;
    }

    public startingValueAt(position: Position): this {
        // @ts-expect-error
        if (this.valueRange === undefined) this.valueRange = {};
        VERIFY(this.valueRange !== undefined);
        this.valueRange.start = position.copy();

        return this;
    }

    public endingValueAt(position: Position): this {
        // @ts-expect-error
        if (this.valueRange === undefined) this.valueRange = {};
        VERIFY(this.valueRange !== undefined);
        this.valueRange.end = position.copy();

        return this;
    }

    public static createWithEmptyNameAndValue(): Attribute {
        return new Attribute('', '');
    }

    public static createWithEmptyValue(name: string): Attribute {
        return new Attribute(name, '');
    }

    public override inspect(indent: number): string {
        return `Attribute { name: '${this.name}', value: '${this.value}' }`;
    }
}

export class AttributeList {
    private attributes: Array<Attribute>;

    public constructor() {
        this.attributes = new Array<Attribute>();
    }

    public get current(): Attribute {
        return this.attributes[this.attributes.length - 1];
    }

    public get list(): Array<Attribute> {
        return this.attributes;
    }

    public nonEmpty(): boolean {
        return this.list.length !== 0;
    }

    public append(attribute: Attribute): void {
        this.attributes.push(attribute);
    }
}
