import unittest
from unittest.mock import MagicMock
from nose.tools import eq_
from numpy import array
from numpy.testing import assert_almost_equal
from helix.calculators.ballast_calculator import BallastCalculator
from helix.calculators.summary_values_calculator import SummaryValuesCalculator
from helix.constants.anchor_type import AnchorType
from helix.constants.module_type_constants.dual_tilt_96_cell_constants import DualTilt96CellConstants
from helix.constants.panel_type import PanelType
from helix.constants.system_type import SystemType
from helix.models.panel import Panel
from helix.models.subarray import Subarray


class SummaryValuesTest(unittest.TestCase):
    def setUp(self):
        self.user_values = MagicMock()
        self.user_values.anchor_type.return_value = AnchorType.OMG_PowerGrip
        self.user_values.max_system_pressure.return_value = 100
        self.user_values.module_system_constants.return_value = DualTilt96CellConstants()
        self.user_values.system_type.return_value = SystemType.dualTilt

        self.c_p_matrix = array([[0.784136, 0.697451, 0.684466, 0.546005],
                                 [0.594876, 0.524444, 0.513894, 0.401395],
                                 [0.368824, 0.324879, 0.318296, 0.248104],
                                 [0.206095, 0.182617, 0.179101, 0.141601],
                                 [0.060000, 0.050000, 0.052000, 0.039000]])
        self.q_z = 37.72825742

        self.subject = SummaryValuesCalculator(self.user_values)
        self.ballast_calculator = BallastCalculator(self.user_values)

    def test_summary_values(self):
        panels = [
            Panel(id=1, ballast=1, wind_anchors=2, pressure=12.89, wind_zone=0, panel_type=PanelType.Corner),
            Panel(id=2, ballast=5, wind_anchors=0, pressure=11.22, wind_zone=1, panel_type=PanelType.NorthSouth),
            Panel(id=3, ballast=0, wind_anchors=4, pressure=2.02, wind_zone=2, panel_type=PanelType.EastWest),
            Panel(id=4, ballast=2, wind_anchors=1, pressure=3.36, wind_zone=3, panel_type=PanelType.Middle),
            Panel(id=5, ballast=0, wind_anchors=0, pressure=20.83, wind_zone=4, panel_type=PanelType.Corner),
        ]

        subarrays = [
            Subarray(subarray_number=0, start_row=0, size=5, required_seismic_anchors=0)
        ]

        seismic_interval = 10

        result = self.subject.summary_values(panels, subarrays, self.c_p_matrix, self.q_z, seismic_interval, self.ballast_calculator)

        expected = [
            {'label': 'Total System Weight (lbs)', 'value': 1943},
            {'label': 'Max PSF', 'value': 20.83},
            {'label': 'Avg PSF', 'value': 10.06},
            {'label': 'Total Anchors', 'value': 7},
            {'label': 'Total Ballast', 'value': 8},
            {'label': 'Max Possible System Weight', 'value': 1563.0},
            {'label': 'Max System Weight Ballast Block', 'value': 16},
            {'label': 'Seismic Anchor Max. Spacing', 'value': seismic_interval}
        ]
        eq_(result, expected)

    def test_documentation_summary_values(self):
        panels = [
            Panel(id=1, ballast=1, wind_anchors=2, pressure=12.89, wind_zone=0, panel_type=PanelType.Corner),
            Panel(id=2, ballast=5, wind_anchors=0, pressure=11.22, wind_zone=1, panel_type=PanelType.NorthSouth),
            Panel(id=3, ballast=0, wind_anchors=4, pressure=2.02, wind_zone=2, panel_type=PanelType.EastWest),
            Panel(id=4, ballast=2, wind_anchors=1, pressure=3.36, wind_zone=3, panel_type=PanelType.Middle),
            Panel(id=5, ballast=0, wind_anchors=0, pressure=20.83, wind_zone=4, panel_type=PanelType.Corner),
        ]

        subarrays = [
            Subarray(subarray_number=0, start_row=0, size=5, required_seismic_anchors=0)
        ]

        seismic_interval = 10

        result = self.subject.documentation_summary_values(panels, subarrays, self.c_p_matrix, self.q_z, seismic_interval, self.ballast_calculator)

        expected = {
            'total_system_weight': 1943,
            'max_psf': 20.83,
            'ave_psf': 10.06,
            'total_anchors': 7,
            'total_ballast': 8,
            'max_possible_system_weight': 1563.0,
            'max_system_weight_ballast_block': 16,
            'seismic_anchor_max_spacing': 10
        }

        eq_(result, expected)

    def test_system_weight_and_pressure(self):
        panels = [
            Panel(id=1, pressure=12.89),
            Panel(id=2, pressure=11.22),
            Panel(id=3, pressure=2.02),
            Panel(id=4, pressure=3.36),
            Panel(id=5, pressure=20.83),
        ]
        assert_almost_equal(self.subject.system_weight_and_pressure(panels), (1943.1261538, 10.064), decimal=6)

    def test_find_max_system_weight(self):
        panels = [
            Panel(id=1, wind_zone=0, panel_type=PanelType.Corner),
            Panel(id=2, wind_zone=1, panel_type=PanelType.NorthSouth),
            Panel(id=3, wind_zone=2, panel_type=PanelType.EastWest),
            Panel(id=4, wind_zone=3, panel_type=PanelType.Middle),
            Panel(id=5, wind_zone=4, panel_type=PanelType.Corner),
        ]

        result = self.subject.find_max_system_weight(panels, self.c_p_matrix, self.q_z, self.ballast_calculator)

        assert_almost_equal(result, (1563, 16), decimal=0)

    def test_find_max_system_weight_does_not_modify_panels_list(self):
        panels = [
            Panel(id=1, wind_zone=0, panel_type=PanelType.Corner),
            Panel(id=2, wind_zone=1, panel_type=PanelType.NorthSouth),
            Panel(id=3, wind_zone=2, panel_type=PanelType.EastWest),
            Panel(id=4, wind_zone=3, panel_type=PanelType.Middle),
            Panel(id=5, wind_zone=4, panel_type=PanelType.Corner),
        ]

        original_panels = list(panels)

        self.subject.find_max_system_weight(panels, self.c_p_matrix, self.q_z, self.ballast_calculator)

        eq_(panels, original_panels)
