"""Tests for scene primitive."""

import xml.etree.ElementTree as et

import pytest

from blc2.functions.scene import Scene
from blc2.constants import INFTY, BXW
from blc2.exceptions import LoadError

def test_scene(aws):
    """Test creation and modification of scenes."""
    c1, c2, c3, c4 = aws.fixtures[0].channels

    s1 = Scene(aws)
    assert s1.scope == frozenset()
    assert s1.scope == frozenset()

    values = {c1: 0, c2: 1, c3: 2, c4: 4}
    s1.values = values
    assert s1.values == values
    assert s1.scope == frozenset(values.keys())

    s1.update({c1: 10})
    assert s1.values[c1] == 10
    assert s1.scope == frozenset(values.keys())
    for c, v in values.items():
        if c == c1:
            continue
        assert v == s1.values[c]

    s1.set(values)
    assert s1.values == values
    assert s1.scope == frozenset(values.keys())

    del s1[c1]
    assert s1.scope == {c2, c3, c4}
    assert c1 not in s1.values
    assert s1[c1] is None

    s1[c1] = 10
    assert s1.scope == frozenset(values.keys())
    assert s1[c1] == 10

    assert s1.duration == INFTY
    assert s1.actual_duration == INFTY
    assert s1.fade_in == 0
    assert s1.fade_out == 0
    assert not s1.audio_scope

    with pytest.raises(Exception):
        s1.duration = 0

    with pytest.raises(Exception):
        s1.actual_duration = 0

    with pytest.raises(Exception):
        s1.fade_in = 0

    with pytest.raises(Exception):
        s1.fade_out = 0

    with pytest.raises(Exception):
        s1.scope = frozenset()

    with pytest.raises(Exception):
        s1.audio_scope = frozenset()

    s1.set(values)
    lc, ac, _ = s1.render(0)
    assert ac == ()
    assert dict(lc) == values

    lc, ac, _ = s1.render(1234567890)
    assert ac == ()
    assert dict(lc) == values

    s1[c1] = 10
    lc, ac, _ = s1.render(1)
    assert dict(lc)[c1] == 10
    assert False not in (v == values[c] for c, v in lc if c != c1)

    with pytest.raises(ValueError):
        s1[c1] = -10
    assert s1[c1] == 10

    with pytest.raises(ValueError):
        s1[c1] = -256
    assert s1[c1] == 10

    assert s1.copy_data(None) is None

    del s1[c4]
    del s1[c4]

def test_scene_serialize(aws, test_xml_eq):
    c1, c2, c3, c4 = aws.fixtures[0].channels
    s = Scene(aws, id_=123, name="Test Scene", values={c1: 1, c2: 2, c3: 3, c4: 4})
    
    (f1, i1), (f2, i2), (f3, i3), (f4, i4) = ((i.f.id, i.id) for i in (c1, c2, c3, c4))
    
    e = s.serialize()
    expected = """
<function xmlns="{bxw}" type="Scene" id="123" name="Test Scene">
    <value fixture="{f1}" channel="{i1}">1</value>
    <value fixture="{f2}" channel="{i2}">2</value>
    <value fixture="{f3}" channel="{i3}">3</value>
    <value fixture="{f4}" channel="{i4}">4</value>
</function>
""".format(bxw=BXW.strip("{}"), f1=f1, f2=f2, f3=f3, f4=f4, i1=i1,i2=i2,i3=i3,i4=i4).replace("\n", "")

    et.register_namespace("", BXW)
    
    assert test_xml_eq(e, expected)

def test_scene_deserialize(aws, test_xml_eq):
    fail = [
        """<function xmlns={} type="asdf"/>""",
        """<asdf/>""",
        """<function xmlns={} type="Scene" id="asdf"/>""",
        """<function xmlns={} type="Scene" id="123" name="Test Scene">
        <asdf/></function>""",
        """<function xmlns={} type="Scene" id="123" name="Test Scene">
        <value/></function>""",
        """<function xmlns={} type="Scene" id="123" name="Test Scene">
        <value fixture="10" channel="45"/></function>""",
        """<function xmlns={} type="Scene" id="123" name="Test Scene">
        <value fixture="0" channel="10"/></function>""",
        """<function xmlns={} type="Scene" id="123" name="Test Scene">
        <value fixture="0" channel="1"/></function>""",
    ]

    for case in fail:
        case = case.format('"'+BXW.strip("{}")+'"')
        with pytest.raises(LoadError):
            Scene.deserialize(aws, et.fromstring(case))


    case = """<function xmlns={} type="Scene" id="123" name="Test Scene">
    	<value fixture="0" channel="0">123</value></function>"""
    case = case.format('"'+BXW.strip("{}")+'"').replace('\n', "")

    s = Scene.deserialize(aws, et.fromstring(case))

    assert test_xml_eq(s.serialize(), case)