# Copyright (c) 2020 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

import re

import hypothesis.strategies as st
import pytest
from hypothesis import given, settings

from czc import json
from czc.string import (
    base64_decode,
    base64_encode,
    camel_case_split,
    camel_to_snake,
    kebab_to_title,
    snake_case_split,
    snake_to_kebab,
    vacuum_pack,
    vacuum_unpack,
)


@pytest.mark.unit
def test_kebab_to_title():
    assert kebab_to_title('big-red-dog') == 'Big Red Dog'
    assert kebab_to_title('dog') == 'Dog'


@pytest.mark.unit
def test_snake_to_kebab():
    assert snake_to_kebab('big_red_dog') == 'big-red-dog'
    assert snake_to_kebab('dog') == 'dog'


@pytest.mark.unit
def test_camel_case_split():
    """
    Assert that we can split various strings that are CamelCased
    """
    assert camel_case_split('foobar') == ['foobar']
    assert camel_case_split(None) == []
    assert camel_case_split('foobar foobar') == ['foobar foobar']
    assert camel_case_split('FooBar') == ['Foo', 'Bar']
    assert camel_case_split('Foo_Bar') == ['Foo_Bar']
    assert camel_case_split('fooBar') == ['foo', 'Bar']
    assert camel_case_split(' foo Bar ') == [' foo Bar ']
    assert camel_case_split('FBar') == ['F', 'Bar']


@pytest.mark.unit
def test_snake_case_split():
    """
    Assert that we can split various strings that are snake_cased
    """
    assert snake_case_split('foobar') == ['foobar']
    assert snake_case_split(None) == []
    assert snake_case_split('foobar foobar') == ['foobar foobar']
    assert snake_case_split('FooBar') == ['FooBar']
    assert snake_case_split('Foo_Bar') == ['Foo', 'Bar']
    assert snake_case_split('fooBar') == ['fooBar']
    assert snake_case_split(' foo Bar ') == [' foo Bar ']
    assert snake_case_split('FBar') == ['FBar']


@pytest.mark.unit
def test_base64_round_trip():
    strings = {'foobar', None, '', json.dumps({'a': 123, 'b': 456}), b'1234567890-'.decode()}
    for s in strings:
        assert s == base64_decode(base64_encode(s))


NO_INF_OR_NAN = {'allow_nan': False, 'allow_infinity': False}

COMMON_INPUTS = st.one_of(
    st.none(),
    st.floats(**NO_INF_OR_NAN),
    st.decimals(**NO_INF_OR_NAN),
    st.lists(st.text()),
    st.dictionaries(st.text(), st.text()),
)


@pytest.mark.unit
@given(COMMON_INPUTS)
@settings(max_examples=100, deadline=5000.00)
def test_vacuum_pack(data):
    pack = vacuum_pack(data)
    unpack = vacuum_unpack(pack)
    if isinstance(data, float):
        assert float(unpack) == data
    else:
        assert unpack == data


@pytest.mark.unit
@given(st.sets(st.text()))
@settings(max_examples=100, deadline=5000.00)
def test_vacuum_pack_sets(data):
    pack = vacuum_pack(data)
    unpack = vacuum_unpack(pack)
    assert set(unpack) == data


@pytest.mark.unit
@given(st.from_regex(r'[A-Za-z_]'))
def test_camel_to_snake(string):
    output = camel_to_snake(string)
    assert not re.match(r'[A-Z]', output)


@pytest.mark.unit
def test_camel_to_snake_examples():
    assert camel_to_snake('userId') == 'user_id'
    assert camel_to_snake('organizationId') == 'organization_id'
    assert camel_to_snake('PrivateApiURL') == 'private_api_url'
