import pytest

import autofit as af
from test_autofit import mock


@pytest.fixture(name="prior_0")
def make_prior_0():
    return af.UniformPrior()


@pytest.fixture(name="prior_1")
def make_prior_1():
    return af.UniformPrior()


@pytest.fixture(name="model")
def make_model(
        prior_0,
        prior_1
):
    model = af.Mapper()

    model.collection = af.Collection([
        prior_0,
        prior_1
    ])

    return model


@pytest.fixture(name="phase")
def make_phase(model):
    return af.AbstractPhase(
        phase_name="phase name",
        model=model
    )


@pytest.fixture(name="results_collection")
def make_results_collection(model):
    collection = af.ResultsCollection()
    instance = af.Instance()
    instance.collection = [1, 2]

    result = mock.Result(
        model=model,
        instance=instance
    )

    collection.add("phase name", result)

    return collection


class TestIteration:
    def test_index_type(
            self,
            phase
    ):
        promise_0 = phase.result.model.collection[0]
        promise_1 = phase.result.model.collection[1]

        assert isinstance(
            promise_0,
            af.Promise
        )
        assert isinstance(
            promise_1,
            af.Promise
        )

    def test_index_populate_model(
            self,
            phase,
            prior_0,
            prior_1,
            results_collection
    ):
        promise_0 = phase.result.model.collection[0]
        promise_1 = phase.result.model.collection[1]

        prior = promise_0.populate(
            results_collection
        )
        assert prior == prior_0

        prior = promise_1.populate(
            results_collection
        )
        assert prior == prior_1

    def test_index_populate_instance(
            self,
            phase,
            prior_0,
            prior_1,
            results_collection
    ):
        promise_0 = phase.result.instance.collection[0]
        promise_1 = phase.result.instance.collection[1]

        value = promise_0.populate(
            results_collection
        )
        assert value == 1

        value = promise_1.populate(
            results_collection
        )
        assert value == 2

    def test_iteration(
            self,
            phase
    ):
        promises = list(phase.result.model.collection)

        assert len(promises) == 2
        assert all([
            isinstance(
                promise,
                af.Promise
            )
            for promise in promises
        ])
