"""Test for `maas.client.viscera.boot_source_selections`."""

import random

from testtools.matchers import (
    Equals,
    MatchesStructure,
)

from .. import (
    boot_source_selections,
    boot_sources,
)
from ...testing import (
    make_name_without_spaces,
    TestCase,
)
from ..testing import bind


def make_origin():
    # Create a new origin with BootSourceSelections and BootSourceSelection.
    # The former refers to the latter via the origin, hence why it must be
    # bound.
    return bind(
        boot_source_selections.BootSourceSelections,
        boot_source_selections.BootSourceSelection,
        boot_sources.BootSource)


def make_boot_source():
    return boot_sources.BootSource({
        "id": random.randint(0, 100),
        "url": "http://images.maas.io/ephemeral-v3/daily/",
        "keyring_filename": (
            "/usr/share/keyrings/ubuntu-cloudimage-keyring.gpg"),
        "keyring_data": "",
    })


class TestBootSourceSelection(TestCase):

    def test__string_representation_includes_defined_keys(self):
        selection = boot_source_selections.BootSourceSelection({
            "os": make_name_without_spaces("os"),
            "release": make_name_without_spaces("release"),
            "arches": [make_name_without_spaces("arch")],
            "subarches": [make_name_without_spaces("subarches")],
            "labels": [make_name_without_spaces("labels")],
        }, {
            "boot_source_id": random.randint(0, 100),
        })
        self.assertThat(repr(selection), Equals(
            "<BootSourceSelection arches=%(arches)r labels=%(labels)r "
            "os=%(os)r release=%(release)r subarches=%(subarches)r>" % (
                selection._data)))

    def test__read(self):
        source = make_boot_source()
        selection_id = random.randint(0, 100)
        os = make_name_without_spaces("os")
        release = make_name_without_spaces("release")
        arches = [make_name_without_spaces("arch")]
        subarches = [make_name_without_spaces("subarches")]
        labels = [make_name_without_spaces("labels")]

        origin = make_origin()
        BootSourceSelection = origin.BootSourceSelection
        BootSourceSelection._handler.read.return_value = {
            "id": selection_id, "os": os, "release": release,
            "arches": arches, "subarches": subarches, "labels": labels}

        selection = BootSourceSelection.read(source, selection_id)
        BootSourceSelection._handler.read.assert_called_once_with(
            boot_source_id=source.id, id=selection_id)
        self.assertThat(selection, MatchesStructure.byEquality(
            id=selection_id,
            boot_source=origin.BootSource(
                source.id, {'bootsourceselection': selection}),
            os=os, release=release,
            arches=arches, subarches=subarches, labels=labels))

    def test__delete(self):
        source = make_boot_source()
        selection_id = random.randint(0, 100)
        os = make_name_without_spaces("os")
        release = make_name_without_spaces("release")
        arches = [make_name_without_spaces("arch")]
        subarches = [make_name_without_spaces("subarches")]
        labels = [make_name_without_spaces("labels")]

        BootSourceSelection = make_origin().BootSourceSelection
        selection = BootSourceSelection({
            "id": selection_id, "os": os, "release": release,
            "arches": arches, "subarches": subarches, "labels": labels}, {
            "boot_source_id": source.id})

        selection.delete()
        BootSourceSelection._handler.delete.assert_called_once_with(
            boot_source_id=source.id, id=selection_id)


class TestBootSources(TestCase):

    def test__read_raises_TypeError_when_no_BootSource(self):
        BootSourceSelections = make_origin().BootSourceSelections
        self.assertRaises(
            TypeError, BootSourceSelections.read, random.randint(0, 100))

    def test__read(self):
        source = make_boot_source()
        origin = make_origin()
        BootSourceSelections = origin.BootSourceSelections
        BootSourceSelections._handler.read.return_value = [
            {
                "id": random.randint(0, 9),
            },
            {
                "id": random.randint(10, 19),
            },
        ]

        selections = BootSourceSelections.read(source)
        self.assertEquals(2, len(selections))
        self.assertEquals(
            origin.BootSource(
                source.id, {'bootsourceselection': selections[0]}),
            selections[0].boot_source)
        self.assertEquals(
            origin.BootSource(
                source.id, {'bootsourceselection': selections[1]}),
            selections[1].boot_source)

    def test__create_raises_TypeError_when_no_BootSource(self):
        os = make_name_without_spaces("os")
        release = make_name_without_spaces("release")

        BootSourceSelections = make_origin().BootSourceSelections

        self.assertRaises(
            TypeError, BootSourceSelections.create,
            random.randint(0, 100), os, release)

    def test__create__without_kwargs(self):
        source = make_boot_source()
        selection_id = random.randint(0, 100)
        os = make_name_without_spaces("os")
        release = make_name_without_spaces("release")

        origin = make_origin()
        BootSourceSelections = origin.BootSourceSelections
        BootSourceSelections._handler.create.return_value = {
            "id": selection_id, "os": os, "release": release,
            "arches": ["*"], "subarches": ["*"], "labels": ["*"]}

        selection = BootSourceSelections.create(source, os, release)
        BootSourceSelections._handler.create.assert_called_once_with(
            boot_source_id=source.id, os=os, release=release,
            arches=["*"], subarches=["*"], labels=["*"])
        self.assertThat(selection, MatchesStructure.byEquality(
            id=selection_id,
            boot_source=origin.BootSource(
                source.id, {'bootsourceselection': selection}),
            os=os, release=release,
            arches=["*"], subarches=["*"], labels=["*"]))

    def test__create__with_kwargs(self):
        source = make_boot_source()
        selection_id = random.randint(0, 100)
        os = make_name_without_spaces("os")
        release = make_name_without_spaces("release")
        arches = [make_name_without_spaces("arch")]
        subarches = [make_name_without_spaces("subarches")]
        labels = [make_name_without_spaces("labels")]

        origin = make_origin()
        BootSourceSelections = origin.BootSourceSelections
        BootSourceSelections._handler.create.return_value = {
            "id": selection_id, "os": os, "release": release,
            "arches": arches, "subarches": subarches, "labels": labels}

        selection = BootSourceSelections.create(
            source, os, release,
            arches=arches, subarches=subarches, labels=labels)
        BootSourceSelections._handler.create.assert_called_once_with(
            boot_source_id=source.id, os=os, release=release,
            arches=arches, subarches=subarches, labels=labels)
        self.assertThat(selection, MatchesStructure.byEquality(
            id=selection_id,
            boot_source=origin.BootSource(
                source.id, {'bootsourceselection': selection}),
            os=os, release=release,
            arches=arches, subarches=subarches, labels=labels))
