import Condition from "./Condition";
import ConditionFactory, {ConditionConfig} from "./ConditionFactory";
import Structure from "../Components/Structure/Structure";
import Input from "../Components/Input/Input";

export default class InputValueCondition extends Condition{
    public targetValue: any = null;
    public equals: boolean = false;
    public greaterThan: boolean = false;
    public smallerThan: boolean = false;
    public not: boolean = false;
    public field: string = '';
    protected _isValid: boolean = false;

    constructor(params: Partial<InputValueCondition>) {
        super(params);
        Object.assign(this, params);
        this.formBuilder.onComponentsCreated.add(() => {
            const item = this.formBuilder.registry[this.field] ?? this.formBuilder.registry[this.idPrefix + this.field];
            if (!(item instanceof Structure || item instanceof Input)) {
                this.check();
                console.warn("Field " + this.field + " is not an input or structure");
                return;
            }
            item.getDataNode().onChange.add(() => {this.check()});
            this.check();
        });
    }

    set isValid(valid: boolean) {
        if (valid === this._isValid) return;
        this._isValid = valid;
        this.onChange.emit(this._isValid);
    }

    get isValid(): boolean {
        return this._isValid;
    }

    public check(): boolean {
        const item = this.formBuilder.registry[this.field];
        if (!(item instanceof Structure || item instanceof Input)){
            this.isValid = true;
            return true;
        }
        const value = item.getDataNode().valueOrDefault;

        let result = true;

        if (this.targetValue === null || this.targetValue === undefined) return true;
        if (this.equals){
            result = typeof value === "object" ? Object.is(value, this.targetValue) : value == this.targetValue;
        }

        if (this.greaterThan){
            result = result && value > this.targetValue;
        }
        if (this.smallerThan){
            result = result && value < this.targetValue;
        }

        if (this.not){
            result = !result;
        }

        this.isValid = result;
        return result;
    }
}

export function addInputValueConditionToFactory(factory: ConditionFactory): void {
    factory.registerConstructor("inputValueCondition", (config, params) => {
        if (!isInputValueConditionConfig(config)) return null;
        const implParams = params as Partial<InputValueCondition>;
        implParams.targetValue = config.targetValue;
        implParams.equals = config.equals;
        implParams.greaterThan = config.greaterThan;
        implParams.smallerThan = config.smallerThan;
        implParams.not = config.not;
        implParams.field = config.field;
        return new InputValueCondition(implParams);
    })
}

function isInputValueConditionConfig(config: ConditionConfig): config is InputValueConditionConfig{
    return config.type === "inputValueCondition";
}

interface InputValueConditionConfig extends ConditionConfig{
    type: "inputValueCondition",
    targetValue: any,
    equals: boolean,
    greaterThan: boolean,
    smallerThan: boolean,
    not: boolean,
    field: string
}