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

from typing import Any

from bu4.evaluation.av.aftervalue import AfterValue
from bu4.evaluation.constructs.evaluable import Evaluable
from bu4.evaluation.constructs.evalue import EValue
from bu4.evaluation.sync import sync
from bu4.evaluation.targets.avtarget import AVTarget

__all__ = ('eproxy', 'antiproxy')


class AVProxyCall(AVTarget):
    def __init__(self, value: Any):
        self.value = value

    def given(self, value: EValue) -> Evaluable:
        if isinstance(value, EProxy):
            return eproxy(self.value(value.value))
        else:
            return eproxy(self.value(antiproxy(value)))


class EProxy(EValue):
    def __init__(self, value: Any):
        super().__init__()
        self.value = value

    def call(self, value: Evaluable) -> Evaluable:
        return AfterValue(value, AVProxyCall(self.value))

    def __str__(self):
        return str(self.value)


class AntiProxy:
    def __init__(self, evaluable: EValue):
        self.evaluable = evaluable

    def __call__(self, value):
        return antiproxy(sync(self.evaluable.call(eproxy(value))))

    def __str__(self):
        return str(self.evaluable)


def eproxy(value: Any) -> Evaluable:
    if isinstance(value, Evaluable):
        return value
    elif isinstance(value, AntiProxy):
        return value.evaluable
    else:
        return EProxy(value)


def antiproxy(evaluable: EValue):
    if isinstance(evaluable, EProxy):
        return evaluable.value
    else:
        return AntiProxy(evaluable)