import csv
import unittest
from unittest.mock import MagicMock

import mockredis
from nose.tools import eq_
from numpy import array
from numpy.testing import assert_array_equal

from helix.calculated_data_repository import CalculatedDataRepository
from helix.store import Store


class CalculatedDataRepositoryTest(unittest.TestCase):
    def setUp(self):
        self.store = Store(mockredis.mock_redis_client(), "foo")
        self.calculator = MagicMock()
        self.subject = CalculatedDataRepository(self.store, self.calculator)

    def test_k_z_forwards_to_calculator(self):
        self.calculator.k_z.return_value = 1.337

        eq_(self.subject.k_z(), 1.337)

    def test_L_B_forwards_to_calculator(self):
        self.calculator.L_B.return_value = 3.14159

        eq_(self.subject.L_B(), 3.14159)

    def test_summary_table_forwards_to_calculator(self):
        self.calculator.summary_table.return_value = 6.28318

        eq_(self.subject.summary_table(), 6.28318)

    def test_minimum_array_sizes_forwards_to_calculator(self):
        self.calculator.minimum_array_sizes.return_value = 2.71828

        eq_(self.subject.minimum_array_sizes(), 2.71828)

    def test_summary_values_acts_as_a_repository(self):
        expected_value = array([
            {'label': 'Total System Weight (lbs)', 'value': 2684},
            {'label': 'Max PSF', 'value': 8.03},
            {'label': 'Avg PSF', 'value': 5.39},
            {'label': 'Total Anchors', 'value': 5},
            {'label': 'Total Ballast', 'value': 131},
            {'label': 'Max Possible System Weight', 'value': 2789.0},
            {'label': 'Max System Weight Ballast Block', 'value': 16},
            {'label': 'Seismic Anchor Max. Spacing', 'value': 12},
        ])

        self.calculator.summary_values.return_value = expected_value

        assert_array_equal(self.subject.summary_values(), expected_value)

        self.calculator.summary_values.return_value = array([])
        assert_array_equal(self.subject.summary_values(), expected_value)

        self.subject.reset_subarray_data()
        assert_array_equal(self.subject.summary_values(), array([]))

    def test_get_computed_csv_columns_acts_as_a_repository(self):
        pass
        # expected_value = DataMatrix(array([[1, Coordinate(2, 2, 3)]]),
        #                             [PanelDataColumn.Ballast, PanelDataColumn.Coordinate])
        #
        # self.calculator.get_computed_csv_columns.return_value = expected_value
        # eq_(self.subject.get_computed_csv_columns(), expected_value)

        # TODO: revisit after getting rid of DataMatrix
        # self.calculator.get_computed_csv_columns.return_value = DataMatrix(array([]), [])
        # eq_(self.subject.get_computed_csv_columns(), expected_value)
        #
        # self.subject.reset_panel_data()
        # eq_(self.subject.get_computed_csv_columns(), DataMatrix(array([]), []))

    def test_compute_bom_acts_as_a_repository(self):
        with open('test/fixtures/expected_dual_tilt_ebom.csv', 'r', newline='') as expected_file:
            expected_csv = expected_file.read()
        reader = csv.reader(expected_csv.splitlines(), dialect='excel-tab')
        expected_bom = array([row for row in reader])

        self.calculator.compute_bom.return_value = expected_bom
        assert_array_equal(self.subject.compute_bom(), expected_bom)

        self.calculator.compute_bom.return_value = array([])
        assert_array_equal(self.subject.compute_bom(), expected_bom)

        self.subject.reset_ebom_data()
        assert_array_equal(self.subject.compute_bom(), array([]))

    def test_subarray_summary_acts_as_a_repository(self):
        expected = array([[1, 435, 170236]])
        self.calculator.subarray_summary.return_value = expected
        assert_array_equal(self.subject.subarray_summary(), expected)

        self.calculator.subarray_summary.return_value = array([])
        assert_array_equal(self.subject.subarray_summary(), expected)

        self.subject.reset_subarray_data()
        assert_array_equal(self.subject.subarray_summary(), array([]))
