import unittest
from unittest.mock import MagicMock

from helix.calculators.mechanical_bom_calculator import MechanicalBomCalculator
from helix.constants.anchor_type import AnchorType
from helix.constants.module_type import ModuleType
from helix.constants.panel_type import PanelType
from helix.constants.parts import *
from helix.constants.system_type import SystemType
from helix.models.panel import Panel
from helix.models.subarray import Subarray
from test.test_helpers import assert_dictionary_equal


class MechanicalBomCalculatorWhenDualTilt96CellTest(unittest.TestCase):
    def setUp(self):
        self.values = MagicMock()
        self.values.system_type.return_value = SystemType.dualTilt
        self.values.anchor_type.return_value = AnchorType.OMG_PowerGrip_Plus
        self.values.module_type.return_value = ModuleType.Cell96

        """
            Generated using the following parameters:
            Building Height = 30
            Building Length = 200
            Building Width = 76
            Parapet Height = 0
            Wind Speed = 125
            Exposure Category = C
            Ballast Block Weight = 13
            Max Allowable System Pressure = 10
            System type = Dual Tilt
        """

        self.panels = [
            Panel(wind_zone=0, panel_type=PanelType.Corner, ballast=4, link_tray=0, cross_tray=0, wind_anchors=1, seismic_anchors=4, subarray=0),
            Panel(wind_zone=0, panel_type=PanelType.NorthSouth, ballast=0, link_tray=0, cross_tray=0, wind_anchors=1, seismic_anchors=0, subarray=0),
            Panel(wind_zone=0, panel_type=PanelType.EastWest, ballast=0, link_tray=0, cross_tray=0, wind_anchors=1, seismic_anchors=0, subarray=0),
            Panel(wind_zone=0, panel_type=PanelType.Middle, ballast=15, link_tray=2, cross_tray=1, wind_anchors=0, seismic_anchors=0, subarray=0),
            Panel(wind_zone=1, panel_type=PanelType.Corner, ballast=0, link_tray=0, cross_tray=0, wind_anchors=1, seismic_anchors=2, subarray=0),
            Panel(wind_zone=1, panel_type=PanelType.NorthSouth, ballast=18, link_tray=2, cross_tray=1, wind_anchors=0, seismic_anchors=0, subarray=0),
            Panel(wind_zone=1, panel_type=PanelType.EastWest, ballast=17, link_tray=2, cross_tray=1, wind_anchors=0, seismic_anchors=0, subarray=0),
            Panel(wind_zone=1, panel_type=PanelType.Middle, ballast=7, link_tray=1, cross_tray=0, wind_anchors=0, seismic_anchors=0, subarray=0),
            Panel(wind_zone=2, panel_type=PanelType.Corner, ballast=12, link_tray=2, cross_tray=0, wind_anchors=0, seismic_anchors=1, subarray=0),
            Panel(wind_zone=2, panel_type=PanelType.NorthSouth, ballast=9, link_tray=1, cross_tray=0, wind_anchors=0, seismic_anchors=0, subarray=0),
            Panel(wind_zone=2, panel_type=PanelType.EastWest, ballast=8, link_tray=2, cross_tray=0, wind_anchors=0, seismic_anchors=0, subarray=0),
            Panel(wind_zone=2, panel_type=PanelType.Middle, ballast=2, link_tray=0, cross_tray=0, wind_anchors=0, seismic_anchors=0, subarray=0),
            Panel(wind_zone=3, panel_type=PanelType.Corner, ballast=5, link_tray=0, cross_tray=0, wind_anchors=0, seismic_anchors=1, subarray=0),
            Panel(wind_zone=3, panel_type=PanelType.NorthSouth, ballast=2, link_tray=0, cross_tray=0, wind_anchors=0, seismic_anchors=0, subarray=0),
            Panel(wind_zone=3, panel_type=PanelType.EastWest, ballast=3, link_tray=0, cross_tray=0, wind_anchors=0, seismic_anchors=0, subarray=0),
            Panel(wind_zone=3, panel_type=PanelType.Middle, ballast=0, link_tray=0, cross_tray=0, wind_anchors=0, seismic_anchors=0, subarray=0),
            Panel(wind_zone=4, panel_type=PanelType.Corner, ballast=0, link_tray=0, cross_tray=0, wind_anchors=0, seismic_anchors=0, subarray=0),
            Panel(wind_zone=4, panel_type=PanelType.NorthSouth, ballast=0, link_tray=0, cross_tray=0, wind_anchors=0, seismic_anchors=0, subarray=0),
            Panel(wind_zone=4, panel_type=PanelType.EastWest, ballast=0, link_tray=0, cross_tray=0, wind_anchors=0, seismic_anchors=0, subarray=0),
            Panel(wind_zone=4, panel_type=PanelType.Middle, ballast=0, link_tray=0, cross_tray=0, wind_anchors=0, seismic_anchors=0, subarray=0),
        ]

        self.subarrays = [
            Subarray(subarray_number=0, required_seismic_anchors=4, row_count=10, column_count=2, row_counted_geometrically=True, column_counted_geometrically=True)
        ]

        self.subject = MechanicalBomCalculator(self.values, self.panels, self.subarrays)

    def build_panel_type_counts(self, corner, north_south, east_west, middle):
        return {
            PanelType.Corner: corner,
            PanelType.NorthSouth: north_south,
            PanelType.EastWest: east_west,
            PanelType.Middle: middle
        }

    def test_compute_mechanical_bom(self):
        expected_output = {
            wire_clip: 80,
            link_tray: 9,
            left_deflector_1_1: 10,
            right_deflector_1_1: 10,
            anchor_plate: 12,
            cross_tray: 3,
            dual_tilt_chassis: 26,
            dual_tilt_platform: 26,
            rubber_foot: 4,
            platform_bolt: 104,
            front_skirt: 20,
            leading_tray: 11,
            ballast: 102,
            anchor: 12,
            anchor_washer: 12,
            module: 40
        }
        assert_dictionary_equal(self.subject.mechanical_bom(), expected_output)

    def test_compute_mechanical_bom_with_fallback_used(self):
        self.subarrays = [
            Subarray(subarray_number=0, required_seismic_anchors=4, row_count=4, column_count=5, row_counted_geometrically=True, column_counted_geometrically=True)
        ]
        self.subject = MechanicalBomCalculator(self.values, self.panels, self.subarrays)

        expected_output = {
            wire_clip: 80,
            link_tray: 18,
            left_deflector_1_1: 10,
            right_deflector_1_1: 10,
            anchor_plate: 12,
            cross_tray: 3,
            dual_tilt_chassis: 26,
            dual_tilt_platform: 26,
            rubber_foot: 4,
            platform_bolt: 104,
            front_skirt: 8,
            leading_tray: 5,
            ballast: 102,
            anchor: 12,
            anchor_washer: 12,
            module: 40
        }
        assert_dictionary_equal(self.subject.mechanical_bom(), expected_output)

