# Copyright (c) 2024 CloudZero - ALL RIGHTS RESERVED - PROPRIETARY AND CONFIDENTIAL
# Unauthorized copying of this file and/or project, via any medium is strictly prohibited.
# Direct all questions to legal@cloudzero.com
from typing import NamedTuple

import pytest

from czc import type_util
from czc.enum_util import AutoExtendEnum
from czc.type_util import deserializable, serializable


class TestEnum(AutoExtendEnum):
    foo = 'foo'
    bar = 'bar'


@deserializable()
class DataObject(NamedTuple):
    name: str
    enum_value: TestEnum


@pytest.mark.unit
@pytest.mark.parametrize('value', ['foo', 'bar', 'new_value'])
def test_auto_extend_enum_should_add_new_values(value):
    assert TestEnum(value).value == value


@pytest.mark.unit
@pytest.mark.parametrize('value', ['foo', 'bar', 'new_value'])
def test_auto_extend_enum_should_work_with_deserializable(value):
    serializable_object = {'name': 'test', 'enum_value': value}
    data_object = type_util.coerce(DataObject, serializable_object)
    assert data_object.enum_value.value == value


@pytest.mark.parametrize('value', ['foo', 'bar', 'new_value'])
def test_auto_extend_enum_should_serialize_correctly(value):
    data_object = DataObject(name='test', enum_value=TestEnum(value))
    serializable_object = serializable(data_object)
    assert serializable_object['enum_value'] == value


@pytest.mark.unit
def test_get_unknown_values_is_empty_when_no_unknown_lookup_occurred():
    class FreshEnum(AutoExtendEnum):
        foo = 'foo'
        bar = 'bar'

    assert FreshEnum.get_unknown_values() == frozenset()


@pytest.mark.unit
def test_get_unknown_values_contains_runtime_added_value():
    class FreshEnum(AutoExtendEnum):
        foo = 'foo'

    FreshEnum('runtime_value')

    assert FreshEnum.get_unknown_values() == frozenset({'runtime_value'})


@pytest.mark.unit
def test_get_unknown_values_isolates_sibling_subclasses():
    class EnumA(AutoExtendEnum):
        a1 = 'a1'

    class EnumB(AutoExtendEnum):
        b1 = 'b1'

    EnumA('extended_a')
    EnumB('extended_b')

    assert EnumA.get_unknown_values() == frozenset({'extended_a'})
    assert EnumB.get_unknown_values() == frozenset({'extended_b'})
