# Funktionsklempner abstract types.
#
# Author: Malte J. Ziebarth (malte.ziebarth@tum.de)
#
# Copyright (C) 2025-2026 Technische Universität München
#
# Licensed under the EUPL, Version 1.2 or – as soon they will be approved by
# the European Commission - subsequent versions of the EUPL (the "Licence");
# You may not use this work except in compliance with the Licence.
# You may obtain a copy of the Licence at:
#
# https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the Licence is distributed on an "AS IS" basis,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the Licence for the specific language governing permissions and
# limitations under the Licence.
#
# SPDX-FileCopyrightText: 2025-2026 Technical University of Munich
# SPDX-License-Identifier: EUPL-1.2
# SPDX-FileContributor: Malte J. Ziebarth <malte.ziebarth@tum.de>

from typing import Any, Iterable, TypeVar, Generic

T0 = TypeVar("T0", covariant=True)

class Pointer(Generic[T0]):
    val: T0

    def __init__(self, val: T0):
        self.val = val

    def __repr__(self):
        return f"POINTER({self.val.__repr__()})"

    def __eq__(self, other: Any) -> bool:
        if isinstance(other, Pointer):
            return self.val == other.val # pyright: ignore
        return False


T1 = TypeVar("T1", covariant=True)

class Const(Generic[T1]):
    val: T1

    def __init__(self, val: T1):
        self.val = val

    def __repr__(self):
        return f"CONST({self.val.__repr__()})"

    def __eq__(self, other: Any) -> bool:
        if isinstance(other, Const):
            return self.val == other.val # pyright: ignore
        return False

T2 = TypeVar("T2", covariant=True)

class Struct(Generic[T2]):
    name: str
    members: tuple[tuple[T2, str], ...]

    def __init__(self, name: str, members: Iterable[tuple[T2, str]]):
        self.name = name
        self.members = tuple(members)

    def __repr__(self) -> str:
        repr = f"struct {self.name} {{"
        for i,m in enumerate(self.members):
            if i > 0:
                repr += ", "
            repr += f"{m[0].__repr__()} {m[1]}"
        return repr + "}"

    def __eq__(self, other: Any):
        return isinstance(other, Struct) and self.name == other.name


T3 = TypeVar("T3", covariant=True)

class Input(Generic[T3]):
    """
    Input that is automatically converted into a corresponding fundamental
    Python type, if possible.
    """
    val: T3

    def __init__(self, val: T3):
        self.val = val

    def __repr__(self):
        return f"INPUT({self.val.__repr__()})"

    def __eq__(self, other: Any) -> bool:
        if type(other) == Input:
            return self.val == other.val # pyright: ignore
        return False


T4 = TypeVar("T4", covariant=True)

class PureInput(Input[T4]):
    """
    Input that is not auto-converted into a corresponding fundamental
    Python type.
    """
    def __repr__(self):
        return f"PURE_INPUT({self.val.__repr__()})"

    def __eq__(self, other: Any) -> bool:
        if type(other) == PureInput:
            return self.val == other.val # pyright: ignore
        return False



T5 = TypeVar("T5", covariant=True)

class Output(Generic[T5]):
    """
    Output that is automatically converted into a corresponding fundamental
    Python type, if possible.
    """
    val: T5

    def __init__(self, val: T5):
        if isinstance(val, Const):
            raise RuntimeError(
                "Output arguments need to be non-const types."
            )
        self.val = val

    def __repr__(self):
        return f"OUTPUT({self.val.__repr__()})"

    def __eq__(self, other: Any) -> bool:
        if isinstance(other, Output):
            return self.val == other.val # pyright: ignore
        return False

T6 = TypeVar("T6", covariant=True)

class PureOutput(Output[T6]):
    """
    Output that is not auto-converted into a corresponding fundamental
    Python type.
    """
    def __repr__(self):
        return f"PURE_OUTPUT({self.val.__repr__()})"

    def __eq__(self, other: Any) -> bool:
        if isinstance(other, Output):
            return self.val == other.val # pyright: ignore
        return False



T7 = TypeVar("T7", covariant=True)

class Temporary(Generic[T7]):
    """
    TemporaryType.
    """
    val: T7

    def __init__(self, val: T7):
        self.val = val

    def __repr__(self):
        return f"Temporary({self.val.__repr__()})"

    def __eq__(self, other: Any) -> bool:
        if type(other) == Input:
            return self.val == other.val # pyright: ignore
        return False