#  Copyright (c) PARRRATE T&V 2021. All rights reserved.

from bu4.evaluation.av.aftervalue import AfterValue
from bu4.evaluation.constructs.eattachable import EAttachable
from bu4.evaluation.constructs.evaluable import Evaluable
from bu4.evaluation.targets.avcall import AVCall
from bu4.indexing.constructs.icall import ICall
from bu4.indexing.constructs.indexed import Indexed
from bu4.linking.constructs.ldelayed import LDelayed
from bu4.linking.constructs.linked import Linked
from bu4.linking.evaluation.elvtype import elvtype
from bu4.transform.states.aftertransform import AfterTransform
from bu4.transform.states.transformfinished import TransformFinished
from bu4.transform.states.transformstart import TransformStart
from bu4.transform.states.transformstate import TransformState
from bu4.transform.targets.atlambda import ATLambda

__all__ = ('LCall',)


class LCall(Linked):
    argument: Linked
    lambda_: Linked

    @classmethod
    def new(cls, argument: Linked, lambda_: Linked) -> Linked:
        return lambda_.value if isinstance(lambda_, LDelayed) else LCall(argument, lambda_)

    def __init__(self, argument: Linked, lambda_: Linked):
        self.argument = argument
        self.lambda_ = lambda_
        self.future = self.argument.future | self.lambda_.future
        self.multifuture = (
                self.argument.multifuture |
                self.lambda_.multifuture |
                (self.argument.future & self.lambda_.future)
        )

    def attach(self, env: elvtype) -> Evaluable:
        return AfterValue(EAttachable(env, self.lambda_), AVCall(EAttachable(env, self.argument)))

    def index(self, promise: list[bytes]) -> TransformState[Indexed]:
        return AfterTransform(
            TransformStart(lambda: self.argument.index(promise)),
            ATLambda(
                lambda argument: AfterTransform(
                    TransformStart(lambda: self.lambda_.index(promise)),
                    ATLambda(
                        lambda lambda_: TransformFinished(ICall(argument, lambda_))
                    )
                )
            )
        )

    def __str__(self):
        return f'/{self.argument}{self.lambda_}'