from decimal import Decimal, Context, getcontext
import random

from bson import Decimal128

from yadm import fields
from yadm.documents import Document


class Doc(Document):
    __collection__ = 'testdocs'
    dec = fields.DecimalField()
    dec128 = fields.Decimal128Field()


def test_to_mongo():
    field = fields.DecimalField()

    data = field.to_mongo(None, Decimal('123.45'))
    assert set(data.keys()) == {'i', 'e'}
    assert data['i'] == 12345
    assert data['e'] == -2


def test_from_mongo():
    field = fields.DecimalField()
    dec = field.from_mongo(None, {'i': 12345, 'e': -2})
    assert dec == Decimal('123.45')


def test_from_mongo__decimal128():
    field = fields.DecimalField()
    dec = field.from_mongo(None, Decimal128('123.45'))
    assert dec == Decimal('123.45')


def test_from_mongo__decimal():
    field = fields.DecimalField()
    dec = field.from_mongo(None, Decimal('123.45'))
    assert dec == Decimal('123.45')


def test_integer_from_digits():
    for _ in range(100):
        digits = [random.randint(0, 9) for _ in range(random.randint(5, 20))]
        integer = fields.DecimalField._integer_from_digits(digits)

    assert integer == int(''.join(str(i) for i in digits))


def test_func_int():
    field = fields.DecimalField()
    dec = field.prepare_value(None, 13)
    assert isinstance(dec, Decimal)
    assert dec == Decimal(13)


def test_func_str():
    field = fields.DecimalField()
    dec = field.prepare_value(None, '3.14')
    assert isinstance(dec, Decimal)
    assert dec == Decimal('3.14')


def test_context_default():
    field = fields.DecimalField()
    assert isinstance(field.context, Context)
    assert field.context == getcontext()


def test_context_init():
    context = Context(prec=5)
    field = fields.DecimalField(context=context)
    assert isinstance(field.context, Context)
    assert field.context == context


def test_save(db):
    doc = Doc()
    doc.dec = Decimal('3.14')
    db.save(doc)

    data = db.db.testdocs.find_one()

    assert 'dec' in data
    assert set(data['dec']) == {'i', 'e'}
    assert data['dec']['i'] == 314
    assert data['dec']['e'] == -2


def test_load(db):
    db.db.testdocs.insert_one({'dec': {'i': 314, 'e': -2}})

    doc = db.get_queryset(Doc).find_one()

    assert hasattr(doc, 'dec')
    assert isinstance(doc.dec, Decimal)
    assert doc.dec == Decimal('3.14')


def test_d128_set():
    doc = Doc()

    doc.dec128 = Decimal128('3.14')
    assert doc.dec128 == Decimal128('3.14')

    doc.dec128 = '13'
    assert doc.dec128 == Decimal128('13')
