import unittest
from unittest.mock import MagicMock

from helix.calculators.ebom_calculator import EbomCalculator, ModuleType
from helix.constants.inverter_type import InverterType
from helix.constants.parts import *
from helix.constants.system_type import SystemType
from test.test_helpers import assert_dictionary_equal


class EbomCalculatorTest(unittest.TestCase):
    def setUp(self):
        self.user_values = MagicMock()
        self.subject = EbomCalculator(self.user_values, 171, 98)

    def test_computes_ebom_without_aux_plugs(self):
        self.user_values.power_stations.return_value = [
            {
                'power_station_id': '1',
                'power_station_description': 'Panel Board 1',
                'power_station_quantity': 1,
                'ac_run_length': 109,
                'inverter_quantity': 2,
                'inverters': [
                    {
                        'model': InverterType.SMA.MODEL_12KW,
                        'strings_per_inverter': 2,
                        'sunshade': False,
                        'dc_switch': True,
                    },
                    {
                        'model': InverterType.SMA.MODEL_15KW,
                        'strings_per_inverter': 5,
                        'sunshade': True,
                        'dc_switch': False,
                    }
                ]
            },
            {
                'power_station_id': '2',
                'power_station_description': 'Panel Board 2',
                'power_station_quantity': 3,
                'ac_run_length': 355,
                'inverter_quantity': 4,
                'inverters': [
                    {
                        'model': InverterType.SMA.MODEL_20KW,
                        'strings_per_inverter': 6,
                        'sunshade': False,
                        'dc_switch': False,
                    },
                    {
                        'model': InverterType.SMA.MODEL_24KW,
                        'strings_per_inverter': 8,
                        'sunshade': False,
                        'dc_switch': False,
                    },
                    {
                        'model': InverterType.SMA.MODEL_24KW,
                        'strings_per_inverter': 8,
                        'sunshade': False,
                        'dc_switch': False,
                    },
                    {
                        'model': InverterType.SMA.MODEL_24KW,
                        'strings_per_inverter': 7,
                        'sunshade': False,
                        'dc_switch': False,
                    }
                ]
            }
        ]
        self.user_values.standalone_inverters.return_value = [
            {
                'standalone_inverter_id': 'key_1',
                'ac_run_length': 57,
                'model': InverterType.SMA.MODEL_20KW,
                'strings_per_inverter': 5,
                'sunshade': True,
                'dc_switch': False,
                'attachment_point': ('Panel Board 1', '1')
            },
            {
                'standalone_inverter_id': 'key_2',
                'ac_run_length': 200,
                'model': InverterType.SMA.MODEL_12KW,
                'strings_per_inverter': 3,
                'sunshade': False,
                'dc_switch': True,
                'attachment_point': ('Switch Gear', None)
            },
            {
                'standalone_inverter_id': 'key_3',
                'ac_run_length': 0,
                'model': InverterType.SMA.MODEL_12KW,
                'strings_per_inverter': 3,
                'sunshade': False,
                'dc_switch': False,
                'attachment_point': ('Panel Board 1', '1')
            },
        ]

        self.user_values.power_monitors.return_values = []

        self.user_values.system_type.return_value = SystemType.dualTilt
        self.user_values.module_type.return_value = ModuleType.Cell96
        expected_output = {
            flat_washer: 100,
            star_washer: 12,
            channel_nut: 16,
            phillips_screw: 12,
            hex_nut_quarter_20: 8,
            hex_nut_three_eighths_16: 100,
            flat_washer_quarter_inch: 8,
            flat_washer_6: 12,
            hex_bolt_quarter_20: 8,
            stump: 102+181,
            wire_clip_large: 2907,
            cable_support_lid: 368,
            cable_support: 368,
            rear_skirt_1_1: -140,
            dc_switch_bracket: 2,
            front_legs: 23,
            back_legs: 23,
            inverter_link: 46,
            inverter_rail: 23,
            sma_20kw_inverter: 4,
            sunshade: 2,
            hex_bolt_3_4: 50,
            panel_board_4: 4,
            ac_inverter_bracket: 3,
            rubber_foot: 69,
            harness_3_string_fm: 13,
            harness_3_string_mf: 13,
            harness_2_string_fm: 3,
            harness_2_string_mf: 3,
            harness_4_string_fm: 15,
            harness_4_string_mf: 15,
            harness_ac_inner: 8,
            harness_ac_outer: 8,
            sma_24kw_inverter: 9,
            sma_12kw_inverter: 3,
            sma_15kw_inverter: 1,
            comm_cable: 12,
            dc_switch_box: 2,
            hex_bolt_1_2: 362,
            whip_tray: 19,
            ac_switch: 3,
            ac_splice_box: 2,
            ethernet_plug: 12.600000000000001,
            mounting_back_plate: 23,
            sunshade_bolt: 4,
            sunshade_washer: 4,
        }

        assert_dictionary_equal(self.subject.compute_ebom(), expected_output)

    def test_computes_ebom_with_delta_inverters(self):
        self.user_values.standalone_inverters.return_value = [
            {
                'standalone_inverter_id': 'key_1',
                'ac_run_length': 57,
                'model': InverterType.DELTA.MODEL_36KW,
                'strings_per_inverter': 8,
                'sunshade': False,
                'dc_switch': False,
                'splice_box': True,
                'attachment_point': ('Switch Gear', None)
            },
            {
                'standalone_inverter_id': 'key_2',
                'ac_run_length': 200,
                'model': InverterType.DELTA.MODEL_42KW,
                'strings_per_inverter': 8,
                'sunshade': False,
                'dc_switch': False,
                'splice_box': False,
                'attachment_point': ('Switch Gear', None)
            },
            {
                'standalone_inverter_id': 'key_3',
                'ac_run_length': 0,
                'model': InverterType.DELTA.MODEL_60KW,
                'strings_per_inverter': 12,
                'sunshade': False,
                'dc_switch': False,
                'splice_box': True,
                'attachment_point': ('Switch Gear', None)
            },
        ]

        self.user_values.system_type.return_value = SystemType.singleTilt
        self.user_values.module_type.return_value = ModuleType.Cell96
        expected_output = {
            stump: 65,
            wire_clip_large: 590,
            cable_support_lid: 0,
            cable_support: 0,
            rear_skirt_1_1: 0,
            rubber_foot: 9,
            delta_inverter_leg: 9,
            harness_4_string_mf: 4,
            harness_4_string_fm: 4,
            delta_36kw_inverter: 1,
            delta_42kw_inverter: 1,
            delta_60kw_inverter: 1,
            delta_splice_box: 2,
            delta_kit_inverter_mount: 3,
            delta_kit_inverter_mount_dt: 0
        }

        assert_dictionary_equal(self.subject.compute_ebom(), expected_output)

    def test_computes_ebom_with_delta_inverters_dual_tilt(self):
        self.user_values.standalone_inverters.return_value = [
            {
                'standalone_inverter_id': 'key_1',
                'ac_run_length': 0,
                'model': InverterType.DELTA.MODEL_42KW,
                'strings_per_inverter': 8,
                'sunshade': False,
                'dc_switch': False,
                'splice_box': False,
                'attachment_point': ('Switch Gear', None)
            },
        ]
        self.user_values.system_type.return_value = SystemType.dualTilt
        self.user_values.module_type.return_value = ModuleType.Cell96
        expected_output = {
            stump: 0,
            wire_clip_large: 200,
            cable_support_lid: 0,
            cable_support: 0,
            rear_skirt_1_1: 0,
            rubber_foot: 3,
            delta_inverter_leg: 3,
            harness_4_string_mf: 2,
            harness_4_string_fm: 2,
            delta_42kw_inverter: 1,
            delta_kit_inverter_mount: 0,
            delta_kit_inverter_mount_dt: 1,
        }
        assert_dictionary_equal(self.subject.compute_ebom(), expected_output)

    def test_computes_ebom_with_aux_plugs(self):
        self.user_values.power_stations.return_value = [
            {
                'power_station_description': 'Panel Board 1',
                'power_station_id': 'panel_board_uuid_1',
                'power_station_quantity': 1,
                'ac_run_length': 0,
                'inverter_quantity': 2,
                'inverters': [
                    {
                        'model': InverterType.SMA.MODEL_12KW,
                        'strings_per_inverter': 2,
                        'sunshade': False,
                        'dc_switch': False,
                    },
                    {
                        'model': InverterType.SMA.MODEL_15KW,
                        'strings_per_inverter': 5,
                        'sunshade': False,
                        'dc_switch': False,
                    }
                ]
            },
            {
                'power_station_description': 'Panel Board 2',
                'power_station_id': 'panel_board_uuid_2',
                'power_station_quantity': 2,
                'ac_run_length': 0,
                'inverter_quantity': 4,
                'inverters': [
                    {
                        'model': InverterType.SMA.MODEL_20KW,
                        'strings_per_inverter': 6,
                        'sunshade': True,
                        'dc_switch': True,
                    },
                    {
                        'model': InverterType.SMA.MODEL_24KW,
                        'strings_per_inverter': 8,
                        'sunshade': True,
                        'dc_switch': True,
                    },
                    {
                        'model': InverterType.SMA.MODEL_24KW,
                        'strings_per_inverter': 8,
                        'sunshade': False,
                        'dc_switch': False,
                    },
                    {
                        'model': InverterType.SMA.MODEL_24KW,
                        'strings_per_inverter': 7,
                        'sunshade': False,
                        'dc_switch': True,
                    }
                ]
            },
            {
                'power_station_description': 'Panel Board 2 (aux)',
                'power_station_id': 'panel_board_uuid_2_aux',
                'power_station_quantity': 1,
                'monitor_id': 'foo',
                'ac_run_length': 0,
                'inverter_quantity': 4,
                'inverters': [
                    {
                        'model': InverterType.SMA.MODEL_20KW,
                        'strings_per_inverter': 6,
                        'sunshade': True,
                        'dc_switch': True,
                    },
                    {
                        'model': InverterType.SMA.MODEL_24KW,
                        'strings_per_inverter': 8,
                        'sunshade': True,
                        'dc_switch': True,
                    },
                    {
                        'model': InverterType.SMA.MODEL_24KW,
                        'strings_per_inverter': 8,
                        'sunshade': False,
                        'dc_switch': False,
                    },
                    {
                        'model': InverterType.SMA.MODEL_24KW,
                        'strings_per_inverter': 7,
                        'sunshade': False,
                        'dc_switch': True,
                    }
                ]
            }
        ]
        self.user_values.power_monitors.return_value = [{
            'monitor_id': 'foo',
            'power_source': ('Panel Board 2 (aux)', 'panel_board_uuid_2_aux')
        }]
        self.user_values.system_type.return_value = SystemType.dualTilt
        self.user_values.module_type.return_value = ModuleType.Cell96
        # 9 dc switches
        expected_output = {
            flat_washer: 76,
            channel_nut: 20,
            hex_nut_quarter_20: 36,
            hex_nut_three_eighths_16: 102,
            flat_washer_quarter_inch: 36,
            hex_bolt_quarter_20: 36,
            monitor_controller_480_v: 1,
            stump: 84,
            dc_switch_bracket: 9,
            front_legs: 19,
            back_legs: 19,
            inverter_link: 38,
            inverter_rail: 19,
            sma_20kw_inverter: 3,
            sunshade: 6,
            hex_bolt_3_4: 64,
            panel_board_4: 2,
            panel_board_4_aux: 1,
            panel_board_2: 1,
            rubber_foot: 57,
            harness_3_string_fm: 10,
            harness_3_string_mf: 10,
            harness_2_string_fm: 2,
            harness_2_string_mf: 2,
            harness_4_string_fm: 15,
            harness_4_string_mf: 15,
            harness_ac_inner: 8,
            harness_ac_outer: 6,
            sma_24kw_inverter: 9,
            sma_12kw_inverter: 1,
            sma_15kw_inverter: 1,
            comm_cable: 11,
            dc_switch_box: 9,
            hex_bolt_1_2: 297,
            whip_tray: 14,
            mounting_back_plate: 19,
            wire_clip_large: 2394,
            cable_support: 270,
            cable_support_lid: 270,
            rear_skirt_1_1: -103,
            ethernet_plug: 7.2,
            monitor_power_plug: 1,
            sunshade_bolt: 12,
            sunshade_washer: 12,
        }

        assert_dictionary_equal(self.subject.compute_ebom(), expected_output)

    def test_computes_ebom_with_aux_plugs_on_switchgear(self):
        self.user_values.power_stations.return_value = [
            {
                'power_station_description': 'Panel Board 1',
                'power_station_id': 'panel_board_uuid_1',
                'power_station_quantity': 1,
                'ac_run_length': 0,
                'inverter_quantity': 2,
                'inverters': [
                    {
                        'model': InverterType.SMA.MODEL_12KW,
                        'strings_per_inverter': 2,
                        'sunshade': False,
                        'dc_switch': False,
                    },
                    {
                        'model': InverterType.SMA.MODEL_15KW,
                        'strings_per_inverter': 5,
                        'sunshade': False,
                        'dc_switch': False,
                    }
                ]
            },
            {
                'power_station_description': 'Panel Board 2',
                'power_station_id': 'panel_board_uuid_2',
                'power_station_quantity': 3,
                'ac_run_length': 0,
                'inverter_quantity': 4,
                'inverters': [
                    {
                        'model': InverterType.SMA.MODEL_20KW,
                        'strings_per_inverter': 6,
                        'sunshade': True,
                        'dc_switch': True,
                    },
                    {
                        'model': InverterType.SMA.MODEL_24KW,
                        'strings_per_inverter': 8,
                        'sunshade': True,
                        'dc_switch': True,
                    },
                    {
                        'model': InverterType.SMA.MODEL_24KW,
                        'strings_per_inverter': 8,
                        'sunshade': False,
                        'dc_switch': False,
                    },
                    {
                        'model': InverterType.SMA.MODEL_24KW,
                        'strings_per_inverter': 7,
                        'sunshade': False,
                        'dc_switch': True,
                    }
                ]
            }
        ]
        self.user_values.power_monitors.return_value = [{
            'monitor_id': 'foo',
            'power_source': ('Switch Gear/External', None)
        }]
        self.user_values.system_type.return_value = SystemType.dualTilt
        self.user_values.module_type.return_value = ModuleType.Cell96
        # 9 dc switches
        expected_output = {
            flat_washer: 76,
            channel_nut: 20,
            hex_nut_quarter_20: 36,
            hex_nut_three_eighths_16: 102,
            flat_washer_quarter_inch: 36,
            hex_bolt_quarter_20: 36,
            monitor_controller_480_v: 1,
            stump: 84,
            dc_switch_bracket: 9,
            front_legs: 19,
            back_legs: 19,
            inverter_link: 38,
            inverter_rail: 19,
            sma_20kw_inverter: 3,
            sunshade: 6,
            hex_bolt_3_4: 64,
            panel_board_4: 3,
            panel_board_2: 1,
            rubber_foot: 57,
            harness_3_string_fm: 10,
            harness_3_string_mf: 10,
            harness_2_string_fm: 2,
            harness_2_string_mf: 2,
            harness_4_string_fm: 15,
            harness_4_string_mf: 15,
            harness_ac_inner: 8,
            harness_ac_outer: 6,
            sma_24kw_inverter: 9,
            sma_12kw_inverter: 1,
            sma_15kw_inverter: 1,
            comm_cable: 10,
            dc_switch_box: 9,
            hex_bolt_1_2: 297,
            whip_tray: 14,
            mounting_back_plate: 19,
            wire_clip_large: 2394,
            cable_support: 270,
            cable_support_lid: 270,
            rear_skirt_1_1: -103,
            ethernet_plug: 7.2,
            monitor_power_plug: 1,
            sunshade_bolt: 12,
            sunshade_washer: 12,
        }

        assert_dictionary_equal(self.subject.compute_ebom(), expected_output)

    def test_computes_ebom_with_aux_plugs_on_switchgear_on_pseries_dual_tilt(self):
        self.user_values.power_stations.return_value = [
            {
                'power_station_description': 'Panel Board 1',
                'power_station_id': 'panel_board_uuid_1',
                'power_station_quantity': 1,
                'ac_run_length': 0,
                'inverter_quantity': 2,
                'inverters': [
                    {
                        'model': InverterType.SMA.MODEL_12KW,
                        'strings_per_inverter': 2,
                        'sunshade': False,
                        'dc_switch': False,
                    },
                    {
                        'model': InverterType.SMA.MODEL_15KW,
                        'strings_per_inverter': 5,
                        'sunshade': False,
                        'dc_switch': False,
                    }
                ]
            },
            {
                'power_station_description': 'Panel Board 2',
                'power_station_id': 'panel_board_uuid_2',
                'power_station_quantity': 3,
                'ac_run_length': 0,
                'inverter_quantity': 4,
                'inverters': [
                    {
                        'model': InverterType.SMA.MODEL_20KW,
                        'strings_per_inverter': 6,
                        'sunshade': True,
                        'dc_switch': True,
                    },
                    {
                        'model': InverterType.SMA.MODEL_24KW,
                        'strings_per_inverter': 8,
                        'sunshade': True,
                        'dc_switch': True,
                    },
                    {
                        'model': InverterType.SMA.MODEL_24KW,
                        'strings_per_inverter': 8,
                        'sunshade': False,
                        'dc_switch': False,
                    },
                    {
                        'model': InverterType.SMA.MODEL_24KW,
                        'strings_per_inverter': 7,
                        'sunshade': False,
                        'dc_switch': True,
                    }
                ]
            }
        ]
        self.user_values.power_monitors.return_value = [{
            'monitor_id': 'foo',
            'power_source': ('Switch Gear/External', None)
        }]
        self.user_values.system_type.return_value = SystemType.dualTilt
        self.user_values.module_type.return_value = ModuleType.PSeries
        # 9 dc switches
        expected_output = {
            flat_washer: 132,
            channel_nut: 20,
            hex_nut_quarter_20: 36,
            hex_nut_three_eighths_16: 130,
            flat_washer_quarter_inch: 36,
            hex_bolt_quarter_20: 36,
            monitor_controller_480_v: 1,
            stump: 84,
            dc_switch_bracket: 9,
            front_legs: 19,
            back_legs: 19,
            inverter_link: 38,
            inverter_rail: 19,
            sma_20kw_inverter: 3,
            sunshade: 6,
            hex_bolt_3_4: 106,
            panel_board_4: 3,
            panel_board_2: 1,
            rubber_foot: 57,
            harness_3_string_fm: 10,
            harness_3_string_mf: 10,
            harness_2_string_fm: 2,
            harness_2_string_mf: 2,
            harness_4_string_fm: 15,
            harness_4_string_mf: 15,
            harness_ac_inner: 8,
            harness_ac_outer: 6,
            sma_24kw_inverter: 9,
            sma_12kw_inverter: 1,
            sma_15kw_inverter: 1,
            comm_cable: 10,
            dc_switch_box: 9,
            hex_bolt_1_2: 297,
            whip_tray: 14,
            mounting_back_plate: 19,
            wire_clip_large: 2394,
            cable_support: 270,
            cable_support_lid: 270,
            rear_skirt_1_1: -103,
            ethernet_plug: 7.2,
            monitor_power_plug: 1,
            fuseshade: 14,
            screw_12_24x1_25: 28,
            fuseshade_brace: 14,
            sunshade_bolt: 12,
            sunshade_washer: 12,
        }

        assert_dictionary_equal(self.subject.compute_ebom(), expected_output)

    def test_computes_ebom_with_power_monitor_DELTA_brand(self):
        self.user_values.inverter_brands.return_value = [{'inverter_brand_id':2}]
        self.user_values.power_monitors.return_value = [{
            'monitor_id': 'foo',
            'power_source': ('Switch Gear/External', None)
        }]
        self.user_values.system_type.return_value = SystemType.singleTilt
        self.user_values.module_type.return_value = ModuleType.Cell96

        expected_output = {
            monitor_power_plug: 1,
            stump: 0,
            cable_support: 0,
            cable_support_lid: 0,
            rear_skirt_1_1: 0,
            monitor_controller_480_v:1,
        }

        assert_dictionary_equal(self.subject.compute_ebom(), expected_output)

    def test_computes_ebom_with_power_monitor_SMA_brand(self):
        self.user_values.inverter_brands.return_value = [{'inverter_brand_id':1}]
        self.user_values.power_monitors.return_value = [{
            'monitor_id': 'foo',
            'power_source': ('Switch Gear/External', None)
        }]
        self.user_values.system_type.return_value = SystemType.singleTilt
        self.user_values.module_type.return_value = ModuleType.Cell96

        expected_output = {
            monitor_power_plug: 1,
            stump: 0,
            cable_support: 0,
            cable_support_lid: 0,
            rear_skirt_1_1: 0,
            monitor_controller_480_v:1,
            flat_washer: 4,
            channel_nut: 4,
            hex_nut_three_eighths_16: 2,
            front_legs: 1,
            back_legs: 1,
            inverter_link: 2,
            inverter_rail: 1,
            rubber_foot: 3,
            hex_bolt_1_2: 9,
            mounting_back_plate: 1,
        }

        assert_dictionary_equal(self.subject.compute_ebom(), expected_output)

    def test_computes_ebom_with_aux_plugs_on_switchgear_on_pseries_single_tilt(self):
        self.user_values.power_stations.return_value = [
            {
                'power_station_description': 'Panel Board 1',
                'power_station_id': 'panel_board_uuid_1',
                'power_station_quantity': 1,
                'ac_run_length': 0,
                'inverter_quantity': 2,
                'inverters': [
                    {
                        'model': InverterType.SMA.MODEL_12KW,
                        'strings_per_inverter': 2,
                        'sunshade': False,
                        'dc_switch': False,
                    },
                    {
                        'model': InverterType.SMA.MODEL_15KW,
                        'strings_per_inverter': 5,
                        'sunshade': False,
                        'dc_switch': False,
                    }
                ]
            },
            {
                'power_station_description': 'Panel Board 2',
                'power_station_id': 'panel_board_uuid_2',
                'power_station_quantity': 3,
                'ac_run_length': 0,
                'inverter_quantity': 4,
                'inverters': [
                    {
                        'model': InverterType.SMA.MODEL_20KW,
                        'strings_per_inverter': 6,
                        'sunshade': True,
                        'dc_switch': True,
                    },
                    {
                        'model': InverterType.SMA.MODEL_24KW,
                        'strings_per_inverter': 8,
                        'sunshade': True,
                        'dc_switch': True,
                    },
                    {
                        'model': InverterType.SMA.MODEL_24KW,
                        'strings_per_inverter': 8,
                        'sunshade': False,
                        'dc_switch': False,
                    },
                    {
                        'model': InverterType.SMA.MODEL_24KW,
                        'strings_per_inverter': 7,
                        'sunshade': False,
                        'dc_switch': True,
                    }
                ]
            }
        ]
        self.user_values.power_monitors.return_value = [{
            'monitor_id': 'foo',
            'power_source': ('Switch Gear/External', None)
        }]
        self.user_values.system_type.return_value = SystemType.singleTilt
        self.user_values.module_type.return_value = ModuleType.PSeries
        # 9 dc switches
        expected_output = {
            flat_washer: 132,
            channel_nut: 20,
            hex_nut_quarter_20: 36,
            hex_nut_three_eighths_16: 130,
            flat_washer_quarter_inch: 36,
            hex_bolt_quarter_20: 36,
            monitor_controller_480_v: 1,
            stump: 84,
            dc_switch_bracket: 9,
            front_legs: 19,
            back_legs: 19,
            inverter_link: 24,
            inverter_rail: 19,
            inverter_link_long: 7,
            inverter_link_short: 7,
            sma_20kw_inverter: 3,
            sunshade: 6,
            hex_bolt_3_4: 106,
            panel_board_4: 3,
            panel_board_2: 1,
            rubber_foot: 57,
            harness_3_string_fm: 10,
            harness_3_string_mf: 10,
            harness_2_string_fm: 2,
            harness_2_string_mf: 2,
            harness_4_string_fm: 15,
            harness_4_string_mf: 15,
            harness_ac_inner: 8,
            harness_ac_outer: 6,
            sma_24kw_inverter: 9,
            sma_12kw_inverter: 1,
            sma_15kw_inverter: 1,
            comm_cable: 10,
            dc_switch_box: 9,
            hex_bolt_1_2: 297,
            whip_tray: 14,
            mounting_back_plate: 19,
            wire_clip_large: 2394,
            cable_support: 694,
            cable_support_lid: 694,
            rear_skirt_1_1: -264,
            ethernet_plug: 7.2,
            monitor_power_plug: 1,
            fuseshade: 14,
            screw_12_24x1_25: 28,
            fuseshade_brace: 14,
            sunshade_bolt: 12,
            sunshade_washer: 12,
        }

        assert_dictionary_equal(self.subject.compute_ebom(), expected_output)

    def test_computes_monitor_type_with_aux_plugs(self):
        self.user_values.power_stations.return_value = [
            {
                'power_station_description': 'Panel Board 1',
                'power_station_id': 'panel_board_uuid_1',
                'power_station_quantity': 1,
                'ac_run_length': 0,
                'inverter_quantity': 2,
                'inverters': [
                    {
                        'model': InverterType.SMA.MODEL_12KW,
                        'strings_per_inverter': 2,
                        'sunshade': False,
                        'dc_switch': False,
                    },
                    {
                        'model': InverterType.SMA.MODEL_15KW,
                        'strings_per_inverter': 5,
                        'sunshade': False,
                        'dc_switch': False,
                    }
                ]
            },
            {
                'power_station_description': 'Panel Board 2',
                'power_station_id': 'panel_board_uuid_2',
                'power_station_quantity': 2,
                'ac_run_length': 0,
                'inverter_quantity': 4,
                'inverters': [
                    {
                        'model': InverterType.SMA.MODEL_20KW,
                        'strings_per_inverter': 6,
                        'sunshade': True,
                        'dc_switch': True,
                    },
                    {
                        'model': InverterType.SMA.MODEL_24KW,
                        'strings_per_inverter': 8,
                        'sunshade': True,
                        'dc_switch': True,
                    },
                    {
                        'model': InverterType.SMA.MODEL_24KW,
                        'strings_per_inverter': 8,
                        'sunshade': False,
                        'dc_switch': False,
                    },
                    {
                        'model': InverterType.SMA.MODEL_24KW,
                        'strings_per_inverter': 7,
                        'sunshade': False,
                        'dc_switch': True,
                    }
                ]
            },
            {
                'power_station_description': 'Panel Board 2 (aux)',
                'power_station_id': 'panel_board_uuid_2_aux',
                'power_station_quantity': 1,
                'monitor_id': 'foo',
                'ac_run_length': 0,
                'inverter_quantity': 4,
                'inverters': [
                    {
                        'model': InverterType.SMA.MODEL_20KW,
                        'strings_per_inverter': 6,
                        'sunshade': True,
                        'dc_switch': True,
                    },
                    {
                        'model': InverterType.SMA.MODEL_24KW,
                        'strings_per_inverter': 8,
                        'sunshade': True,
                        'dc_switch': True,
                    },
                    {
                        'model': InverterType.SMA.MODEL_24KW,
                        'strings_per_inverter': 8,
                        'sunshade': False,
                        'dc_switch': False,
                    },
                    {
                        'model': InverterType.SMA.MODEL_24KW,
                        'strings_per_inverter': 7,
                        'sunshade': False,
                        'dc_switch': True,
                    }
                ]
            }
        ]
        self.user_values.power_monitors.return_value = [{
            'monitor_id': 'foo',
            'power_source': ('Panel Board 2 (aux)', 'panel_board_uuid_2_aux')
        }]

        self.user_values.system_type.return_value = SystemType.dualTilt

        # 9 dc switches
        expected_output_480 = {
            flat_washer: 76,
            channel_nut: 20,
            hex_nut_quarter_20: 36,
            hex_nut_three_eighths_16: 102,
            flat_washer_quarter_inch: 36,
            hex_bolt_quarter_20: 36,
            monitor_controller_480_v: 1,
            stump: 84,
            dc_switch_bracket: 9,
            front_legs: 19,
            back_legs: 19,
            inverter_link: 38,
            inverter_rail: 19,
            sma_20kw_inverter: 3,
            sunshade: 6,
            hex_bolt_3_4: 64,
            panel_board_4: 2,
            panel_board_4_aux: 1,
            panel_board_2: 1,
            rubber_foot: 57,
            harness_3_string_fm: 10,
            harness_3_string_mf: 10,
            harness_2_string_fm: 2,
            harness_2_string_mf: 2,
            harness_4_string_fm: 15,
            harness_4_string_mf: 15,
            harness_ac_inner: 8,
            harness_ac_outer: 6,
            sma_24kw_inverter: 9,
            sma_12kw_inverter: 1,
            sma_15kw_inverter: 1,
            comm_cable: 11,
            dc_switch_box: 9,
            hex_bolt_1_2: 297,
            whip_tray: 14,
            mounting_back_plate: 19,
            wire_clip_large: 2394,
            cable_support: 270,
            cable_support_lid: 270,
            rear_skirt_1_1: -103,
            ethernet_plug: 7.2,
            monitor_power_plug: 1,
            sunshade_bolt: 12,
            sunshade_washer: 12,
        }

        expected_output_240 = {
            flat_washer: 72,
            channel_nut: 16,
            hex_nut_quarter_20: 36,
            hex_nut_three_eighths_16: 100,
            flat_washer_quarter_inch: 36,
            hex_bolt_quarter_20: 36,
            monitor_controller_240_v: 1,
            stump: 84,
            dc_switch_bracket: 9,
            front_legs: 18,
            back_legs: 18,
            inverter_link: 36,
            inverter_rail: 18,
            sma_20kw_inverter: 3,
            sunshade: 6,
            hex_bolt_3_4: 64,
            panel_board_4: 3,
            panel_board_2: 1,
            rubber_foot: 54,
            harness_3_string_fm: 10,
            harness_3_string_mf: 10,
            harness_2_string_fm: 2,
            harness_2_string_mf: 2,
            harness_4_string_fm: 15,
            harness_4_string_mf: 15,
            harness_ac_inner: 8,
            harness_ac_outer: 6,
            sma_24kw_inverter: 9,
            sma_12kw_inverter: 1,
            sma_15kw_inverter: 1,
            comm_cable: 10,
            dc_switch_box: 9,
            hex_bolt_1_2: 288,
            whip_tray: 14,
            mounting_back_plate: 18,
            wire_clip_large: 2394,
            cable_support: 270,
            cable_support_lid: 270,
            rear_skirt_1_1: -103,
            ethernet_plug: 7.2,
            sunshade_bolt: 12,
            sunshade_washer: 12,
        }

        self.user_values.module_type.return_value = ModuleType.Cell96

        self.subject = EbomCalculator(self.user_values, 171, 98, 306)
        assert_dictionary_equal(self.subject.compute_ebom(), expected_output_480)

        self.subject = EbomCalculator(self.user_values, 171, 98, 400)
        assert_dictionary_equal(self.subject.compute_ebom(), expected_output_480)

        self.subject = EbomCalculator(self.user_values, 171, 98, 304)
        assert_dictionary_equal(self.subject.compute_ebom(), expected_output_240)

        self.subject = EbomCalculator(self.user_values, 171, 98, 100)
        assert_dictionary_equal(self.subject.compute_ebom(), expected_output_240)

        self.user_values.module_type.return_value = ModuleType.Cell128

        self.subject = EbomCalculator(self.user_values, 171, 98, 230)
        assert_dictionary_equal(self.subject.compute_ebom(), expected_output_480)

        self.subject = EbomCalculator(self.user_values, 171, 98, 400)
        assert_dictionary_equal(self.subject.compute_ebom(), expected_output_480)

        self.subject = EbomCalculator(self.user_values, 171, 98, 229)
        assert_dictionary_equal(self.subject.compute_ebom(), expected_output_240)

        self.subject = EbomCalculator(self.user_values, 171, 98, 100)
        assert_dictionary_equal(self.subject.compute_ebom(), expected_output_240)

    def test_computes_monitor_type_with_aux_plugs_on_switchgear(self):
        self.user_values.power_stations.return_value = []
        self.user_values.power_monitors.return_value = [{
            'monitor_id': 'foo',
            'power_source': ('Switch Gear/External', None)
        }]

        self.user_values.system_type.return_value = SystemType.dualTilt

        # 9 dc switches
        expected_output_480 = {
            flat_washer: 4,
            channel_nut: 4,
            hex_nut_three_eighths_16: 2,
            monitor_controller_480_v: 1,
            stump: 0,
            front_legs: 1,
            back_legs: 1,
            inverter_link: 2,
            inverter_rail: 1,
            rubber_foot: 3,
            hex_bolt_1_2: 9,
            mounting_back_plate: 1,
            cable_support: 0,
            cable_support_lid: 0,
            rear_skirt_1_1: 0,
            monitor_power_plug: 1,
        }

        expected_output_480_pseries = {
            flat_washer: 4,
            channel_nut: 4,
            hex_nut_three_eighths_16: 2,
            monitor_controller_480_v: 1,
            stump: 0,
            front_legs: 1,
            back_legs: 1,
            inverter_link: 2,
            inverter_rail: 1,
            rubber_foot: 3,
            hex_bolt_1_2: 9,
            mounting_back_plate: 1,
            cable_support: 0,
            cable_support_lid: 0,
            rear_skirt_1_1: 0,
            monitor_power_plug: 1,
        }

        expected_output_240 = {
            monitor_controller_240_v: 1,
            stump: 0,
            cable_support: 0,
            cable_support_lid: 0,
            rear_skirt_1_1: 0
        }

        expected_output_240_pseries = {
            stump: 0,
            cable_support_lid: 0,
            cable_support: 0,
            rear_skirt_1_1: 0,
            monitor_controller_240_v: 1,
        }

        self.user_values.module_type.return_value = ModuleType.Cell96

        self.subject = EbomCalculator(self.user_values, 171, 98, 306)
        assert_dictionary_equal(self.subject.compute_ebom(), expected_output_480)

        self.subject = EbomCalculator(self.user_values, 171, 98, 304)
        assert_dictionary_equal(self.subject.compute_ebom(), expected_output_240)

        self.user_values.module_type.return_value = ModuleType.Cell128

        self.subject = EbomCalculator(self.user_values, 171, 98, 230)
        assert_dictionary_equal(self.subject.compute_ebom(), expected_output_480)

        self.subject = EbomCalculator(self.user_values, 171, 98, 300)
        assert_dictionary_equal(self.subject.compute_ebom(), expected_output_480)

        self.subject = EbomCalculator(self.user_values, 171, 98, 229)
        assert_dictionary_equal(self.subject.compute_ebom(), expected_output_240)

        self.subject = EbomCalculator(self.user_values, 171, 98, 104)
        assert_dictionary_equal(self.subject.compute_ebom(), expected_output_240)

        self.user_values.module_type.return_value = ModuleType.PSeries

        self.subject = EbomCalculator(self.user_values, 171, 98, 286)
        assert_dictionary_equal(self.subject.compute_ebom(), expected_output_480_pseries)

        self.subject = EbomCalculator(self.user_values, 171, 98, 300)
        assert_dictionary_equal(self.subject.compute_ebom(), expected_output_480_pseries)

        self.subject = EbomCalculator(self.user_values, 171, 98, 285)
        assert_dictionary_equal(self.subject.compute_ebom(), expected_output_240_pseries)

        self.subject = EbomCalculator(self.user_values, 171, 98, 104)
        assert_dictionary_equal(self.subject.compute_ebom(), expected_output_240_pseries)

    def test_computes_ebom_with_power_monitor_DELTA_brand(self):
        self.user_values.inverter_brands.return_value = [{'inverter_brand_id':2}]
        self.user_values.power_monitors.return_value = [{
            'monitor_id': 'foo',
            'power_source': ('Switch Gear/External', None)
        }]
        self.user_values.system_type.return_value = SystemType.singleTilt
        self.user_values.module_type.return_value = ModuleType.Cell96

        expected_output = {
            monitor_power_plug: 1,
            stump: 0,
            cable_support: 0,
            cable_support_lid: 0,
            rear_skirt_1_1: 0,
            monitor_controller_480_v: 1,
        }

        assert_dictionary_equal(self.subject.compute_ebom(), expected_output)

    def test_computes_ebom_with_power_monitor_SMA_brand(self):
        self.user_values.inverter_brands.return_value = [{'inverter_brand_id':1}]
        self.user_values.power_monitors.return_value = [{
            'monitor_id': 'foo',
            'power_source': ('Switch Gear/External', None)
        }]
        self.user_values.system_type.return_value = SystemType.singleTilt
        self.user_values.module_type.return_value = ModuleType.Cell96

        expected_output = {
            monitor_power_plug: 1,
            stump: 0,
            cable_support: 0,
            cable_support_lid: 0,
            rear_skirt_1_1: 0,
            monitor_controller_480_v:1,
            flat_washer: 4,
            channel_nut: 4,
            hex_nut_three_eighths_16: 2,
            front_legs: 1,
            back_legs: 1,
            inverter_link: 2,
            inverter_rail: 1,
            rubber_foot: 3,
            hex_bolt_1_2: 9,
            mounting_back_plate: 1,
        }

        assert_dictionary_equal(self.subject.compute_ebom(), expected_output)
