import {Tag} from "./Tag";
import {TagsFilter} from "./TagsFilter";

export class RegexTag extends TagsFilter {
    private readonly key: RegExp | string;
    private readonly value: RegExp | string;
    private readonly invert: boolean;
    private readonly matchesEmpty: boolean

    constructor(key: string | RegExp, value: RegExp | string, invert: boolean = false) {
        super();
        this.key = key;
        this.value = value;
        this.invert = invert;
        this.matchesEmpty = RegexTag.doesMatch("", this.value);
    }

    private static doesMatch(fromTag: string, possibleRegex: string | RegExp): boolean {
        if (typeof possibleRegex === "string") {
            return fromTag === possibleRegex;
        }
        return fromTag.match(possibleRegex) !== null;
    }

    private static source(r: string | RegExp) {
        if (typeof (r) === "string") {
            return r;
        }
        return r.source;
    }

    asOverpass(): string[] {
        if (typeof this.key === "string") {
            return [`['${this.key}'${this.invert ? "!" : ""}~'${RegexTag.source(this.value)}']`];
        }
        return [`[~'${this.key.source}'${this.invert ? "!" : ""}~'${RegexTag.source(this.value)}']`];
    }

    isUsableAsAnswer(): boolean {
        return false;
    }

    matchesProperties(tags: any): boolean {
        for (const key in tags) {
            if (RegexTag.doesMatch(key, this.key)) {
                const value = tags[key]
                return RegexTag.doesMatch(value, this.value) != this.invert;
            }
        }
        if (this.matchesEmpty) {
            // The value is 'empty'
            return !this.invert;
        }
        // The matching key was not found
        return this.invert;
    }

    asHumanString() {
        if (typeof this.key === "string") {
            return `${this.key}${this.invert ? "!" : ""}~${RegexTag.source(this.value)}`;
        }
        return `${this.key.source}${this.invert ? "!" : ""}~~${RegexTag.source(this.value)}`
    }

    isEquivalent(other: TagsFilter): boolean {
        if (other instanceof RegexTag) {
            return other.asHumanString() == this.asHumanString();
        }
        if (other instanceof Tag) {
            return RegexTag.doesMatch(other.key, this.key) && RegexTag.doesMatch(other.value, this.value);
        }
        return false;
    }

    usedKeys(): string[] {
        if (typeof this.key === "string") {
            return [this.key];
        }
        throw "Key cannot be determined as it is a regex"
    }

    asChange(properties: any): { k: string; v: string }[] {
        if(this.invert){
            return []
        }
        if (typeof this.key === "string") {
            if( typeof this.value === "string"){
                return [{k: this.key, v: this.value}]
            }
            if(this.value.toString() != "/^..*$/"){
                console.warn("Regex value in tag; using wildcard:", this.key, this.value)
            }
            return [{k: this.key, v: undefined}]
        }
        console.error("Cannot export regex tag to asChange; ", this.key, this.value)
        return []
    }
}