package prolog.ast.terms

import prolog.Answers
import prolog.Substitutions
import prolog.ast.arithmetic.Expression
import prolog.ast.arithmetic.Simplification
import prolog.ast.logic.LogicOperand

open class Variable(val name: String) : Term, Body, Expression, LogicOperand() {
    override fun simplify(subs: Substitutions): Simplification {
        // If the variable is bound, return the value of the binding
        // If the variable is not bound, return the variable itself
        var result = this as Term
        if (this in subs) {
            val boundTerm = subs[this]!!
            result = if (boundTerm is Expression) boundTerm.simplify(subs).to else boundTerm
        }
        return Simplification(this, result)
    }

    override fun satisfy(subs: Substitutions): Answers {
        // If the variable is bound, satisfy the bound term
        if (this in subs) {
            val boundTerm = subs[this]!! as Body
            return boundTerm.satisfy(subs)
        }

        return sequenceOf(Result.failure(IllegalArgumentException("Unbound variable: $this")))
    }

    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (other == null || other !is Variable) return false
        return name == other.name
    }

    override fun applySubstitution(subs: Substitutions): Variable = this

    override fun hashCode(): Int {
        return name.hashCode()
    }

    override fun toString(): String = name
}