import unittest
import mockredis
from numpy.testing import assert_array_equal
from helix.calculators.calculator import Calculator
from helix.constants.anchor_type import AnchorType
from helix.constants.exposure_category import ExposureCategory
from helix.constants.module_type import ModuleType
from helix.constants.system_type import SystemType
from helix.models.sql.sites import Site
from helix.store import Store
from helix.user_values import UserValues


class BomIntegrationTest(unittest.TestCase):
    def test_lwoods_2381(self):  # name of the site
        self.store = mockredis.mock_redis_client()
        self.site = Site()
        self.values = UserValues(self.store, self.site)
        self.site.building_height = 40
        self.site.building_width = 87
        self.site.building_length = 195
        self.site.parapet_height = 0.3
        self.site.wind_speed = 130
        self.site.exposure_category = ExposureCategory.B.value
        self.site.ballast_block_weight = 14
        self.site.max_psf= 10
        self.site.anchor_type = AnchorType.OMG_PowerGrip_Plus.value
        self.site.spectral_response = 1

        self.site.system_type = SystemType(SystemType.dualTilt.value)
        self.site.module_type = ModuleType(ModuleType.Cell96.value)
        with open('test/fixtures/input_dual_tilt_96_cell_lw_2381.tsv', 'r', newline='') as csv_file:
            csv_content = csv_file.read()
        self.site.cad_file = csv_content
        self.subject = Calculator(self.values)

        expected = [
            ["512200", "CLIP, WIRE FORMED, CABLE MANAGEMENT, INSIDE, 352MM ^ 2", "510"],
            ["513833", "TRAY, LINK, HELIX ROOF", "78"],
            ["513843", "PLATE, ANCHOR, HELIX ROOF", "86"],
            ["513844", "TRAY, OPTIONAL BALLAST, HELIX ROOF", "35"],
            ["514056", "BASE, CHASSIS, DUAL TILT, HELIX ROOF", "147"],
            ["514057", "PLATFORM, CHASSIS, DUAL TILT, HELIX ROOF", "147"],
            ["514265", "FOOT, RECYCLED RUBBER, HELIX ROOF", "26"],
            ["515063", "SCREW, CAP, SH, M6 X 1 X 12, 18-8 SS (DIN 912)", "600"],
            ["515928", "FRONT SKIRT, HELIX ROOF", "126"],
            ["517871", "TRAY, LEADING, HELIX ROOF, RIVETED VERSION", "67"],
            ["518477", "WASHER, FLAT, 3/8, 1.00 OD, 18-8 SS", "100"],
            ["521794", "DEFLECTOR, LH, HELIX ROOF V1.1", "30"],
            ["521795", "DEFLECTOR, RH, HELIX ROOF V1.1", "30"],
            ["Contractor Supplied", "Ballast Blocks", "610"],
            ["TBD", "Anchors", "86"],
            ["TBD", "Modules", "252"]
        ]

        bom = self.subject.compute_bom()
        assert_array_equal(bom, expected)

    def test_lw_2394(self):
        self.store = Store(mockredis.mock_redis_client(), "foo")
        self.site = Site()
        self.values = UserValues(self.store, self.site)
        self.site.building_height = 40
        self.site.building_width = 88.25
        self.site.building_length = 195.25
        self.site.parapet_height = 0.3333
        self.site.wind_speed = 130
        self.site.exposure_category = ExposureCategory.B_C.value
        self.site.exposure_transition_distance = 1212
        self.site.ballast_block_weight = 14
        self.site.max_psf= 10
        self.site.anchor_type = AnchorType.OMG_PowerGrip_Plus.value
        self.site.spectral_response = 0.993

        self.site.system_type = SystemType(SystemType.dualTilt.value)
        self.site.module_type = ModuleType(ModuleType.Cell96.value)
        with open('test/fixtures/input_dual_tilt_96_cell_lw_2394.tsv', 'r', newline='') as csv_file:
            csv_content = csv_file.read()
        self.site.cad_file= csv_content
        self.subject = Calculator(self.values)

        expected = [
            ['512200', 'CLIP, WIRE FORMED, CABLE MANAGEMENT, INSIDE, 352MM ^ 2', '540'],
            ['513833', 'TRAY, LINK, HELIX ROOF', '75'],    # TODO: should be 73 for part perfect bom
            ['513843', 'PLATE, ANCHOR, HELIX ROOF', '114'],
            ['513844', 'TRAY, OPTIONAL BALLAST, HELIX ROOF', '17'],
            ['514056', 'BASE, CHASSIS, DUAL TILT, HELIX ROOF', '148'],
            ['514057', 'PLATFORM, CHASSIS, DUAL TILT, HELIX ROOF', '148'],
            ['514265', 'FOOT, RECYCLED RUBBER, HELIX ROOF', '27'],
            ['515063', 'SCREW, CAP, SH, M6 X 1 X 12, 18-8 SS (DIN 912)', '600'],
            ['515928', 'FRONT SKIRT, HELIX ROOF', '130'],
            ['517871', 'TRAY, LEADING, HELIX ROOF, RIVETED VERSION', '69'],
            ['518477', 'WASHER, FLAT, 3/8, 1.00 OD, 18-8 SS', '125'],
            ["521794", "DEFLECTOR, LH, HELIX ROOF V1.1", "20"],
            ["521795", "DEFLECTOR, RH, HELIX ROOF V1.1", "20"],
            ['Contractor Supplied', 'Ballast Blocks', '358'],
            ['TBD', 'Anchors', '114'],
            ['TBD', 'Modules', '264']
        ]

        bom = self.subject.compute_bom()
        assert_array_equal(bom, expected)

    def test_lw_5510(self):
        self.store = Store(mockredis.mock_redis_client(), "foo")
        self.site = Site()
        self.values = UserValues(self.store, self.site)
        self.site.building_height = 40
        self.site.building_width = 86.75
        self.site.building_length = 210.33
        self.site.parapet_height = 1
        self.site.wind_speed = 130
        self.site.exposure_category = ExposureCategory.B.value
        self.site.ballast_block_weight = 14
        self.site.max_psf= 10
        self.site.anchor_type = AnchorType.OMG_PowerGrip_Plus.value
        self.site.spectral_response = 1.009

        self.site.system_type = SystemType(SystemType.dualTilt.value)
        self.site.module_type = ModuleType(ModuleType.Cell96.value)
        with open('test/fixtures/input_dual_tilt_96_cell_lw_5510.tsv', 'r', newline='') as csv_file:
            csv_content = csv_file.read()
        self.site.cad_file = csv_content
        self.subject = Calculator(self.values)

        expected = [
            ['512200', 'CLIP, WIRE FORMED, CABLE MANAGEMENT, INSIDE, 352MM ^ 2', '330'],
            ['513833', 'TRAY, LINK, HELIX ROOF', '45'], # 45 is perfect value for this bom
            ['513843', 'PLATE, ANCHOR, HELIX ROOF', '67'],
            ['513844', 'TRAY, OPTIONAL BALLAST, HELIX ROOF', '13'],
            ['514056', 'BASE, CHASSIS, DUAL TILT, HELIX ROOF', '102'],
            ['514057', 'PLATFORM, CHASSIS, DUAL TILT, HELIX ROOF', '102'],
            ['514265', 'FOOT, RECYCLED RUBBER, HELIX ROOF', '16'],
            ['515063', 'SCREW, CAP, SH, M6 X 1 X 12, 18-8 SS (DIN 912)', '450'],
            ['515928', 'FRONT SKIRT, HELIX ROOF', '88'],
            ['517871', 'TRAY, LEADING, HELIX ROOF, RIVETED VERSION', '53'],
            ['518477', 'WASHER, FLAT, 3/8, 1.00 OD, 18-8 SS', '75'],
            ["521794", "DEFLECTOR, LH, HELIX ROOF V1.1", "36"],
            ["521795", "DEFLECTOR, RH, HELIX ROOF V1.1", "36"],
            ['Contractor Supplied', 'Ballast Blocks', '286'],
            ['TBD', 'Anchors', '67'],
            ['TBD', 'Modules', '160'],
        ]

        bom = self.subject.compute_bom()
        assert_array_equal(bom, expected)

    def test_al_2400(self):
        self.store = Store(mockredis.mock_redis_client(), "foo")
        self.site = Site()
        self.values = UserValues(self.store, self.site)
        self.site.building_height = 40
        self.site.building_width = 189
        self.site.building_length = 81
        self.site.parapet_height = 0
        self.site.wind_speed = 130
        self.site.exposure_category = ExposureCategory.B_C.value
        self.site.exposure_transition_distance = 1500
        self.site.module_type = ModuleType.Cell96.value
        self.site.ballast_block_weight = 14
        self.site.max_psf = 10
        self.site.anchor_type = AnchorType.OMG_PowerGrip_Plus.value
        self.site.spectral_response = 0.994

        self.site.system_type = SystemType.dualTilt.value
        with open('test/fixtures/input_dual_tilt_96_cell_al_2400.tsv', 'r', newline='') as csv_file:
            csv_content = csv_file.read()
        self.site.cad_file = csv_content
        self.subject = Calculator(self.values)

        expected = [
            ['512200', 'CLIP, WIRE FORMED, CABLE MANAGEMENT, INSIDE, 352MM ^ 2', '510'],
            ['513833', 'TRAY, LINK, HELIX ROOF', '73'], # TODO: should be 70 for part perfect bom
            ['513843', 'PLATE, ANCHOR, HELIX ROOF', '94'],
            ['513844', 'TRAY, OPTIONAL BALLAST, HELIX ROOF', '28'],
            ['514056', 'BASE, CHASSIS, DUAL TILT, HELIX ROOF', '140'],
            ['514057', 'PLATFORM, CHASSIS, DUAL TILT, HELIX ROOF', '140'],
            ['514265', 'FOOT, RECYCLED RUBBER, HELIX ROOF', '25'],
            ['515063', 'SCREW, CAP, SH, M6 X 1 X 12, 18-8 SS (DIN 912)', '600'],
            ['515928', 'FRONT SKIRT, HELIX ROOF', '120'],
            ['517871', 'TRAY, LEADING, HELIX ROOF, RIVETED VERSION', '64'],
            ['518477', 'WASHER, FLAT, 3/8, 1.00 OD, 18-8 SS', '100'],
            ["521794", "DEFLECTOR, LH, HELIX ROOF V1.1", "24"],
            ["521795", "DEFLECTOR, RH, HELIX ROOF V1.1", "24"],
            ['Contractor Supplied', 'Ballast Blocks', '560'],
            ['TBD', 'Anchors', '94'],
            ['TBD', 'Modules', '244'],
        ]

        bom = self.subject.compute_bom()
        assert_array_equal(bom, expected)

    def test_array2(self):
        """
        Pivotal: 1544689
        """
        self.store = Store(mockredis.mock_redis_client(), "foo")
        self.site = Site()
        self.values = UserValues(self.store, self.site)
        self.site.building_height = 45
        self.site.building_width = 383
        self.site.building_length = 430
        self.site.parapet_height = 0.3
        self.site.wind_speed = 110
        self.site.exposure_category = ExposureCategory.C.value
        self.site.exposure_transition_distance = 1500
        self.site.module_type = ModuleType.Cell96.value
        self.site.ballast_block_weight = 14
        self.site.max_psf = 6
        self.site.anchor_type = AnchorType.OMG_PowerGrip_Plus.value
        self.site.spectral_response = 1.03

        self.site.system_type = SystemType.dualTilt.value
        with open('test/fixtures/input_dual_tilt_96_cell_array_2.tsv', 'r', newline='') as csv_file:
            csv_content = csv_file.read()
        self.site.cad_file = csv_content
        self.subject = Calculator(self.values)

        expected_link = [
            ['513833', 'TRAY, LINK, HELIX ROOF', '50'],
        ]
        expected_link_num = expected_link[0][2]

        bom = self.subject.compute_bom()
        links_in_bom = [elem[2] for elem in bom if elem[0] == '513833'][0]

        self.assertEqual(expected_link_num, links_in_bom)

    def test_array1(self):
        """
        Pivotal: 1544689
        """
        self.store = Store(mockredis.mock_redis_client(), "foo")
        self.site = Site()
        self.values = UserValues(self.store, self.site)
        self.site.building_height = 45
        self.site.building_width = 383
        self.site.building_length = 430
        self.site.parapet_height = 0.3
        self.site.wind_speed = 110
        self.site.exposure_category = ExposureCategory.C.value
        self.site.exposure_transition_distance = 1500
        self.site.module_type = ModuleType.Cell96.value
        self.site.ballast_block_weight = 14
        self.site.max_psf = 10
        self.site.anchor_type = AnchorType.OMG_PowerGrip_Plus.value
        self.site.spectral_response = 1.03

        self.site.system_type = SystemType.dualTilt.value
        with open('test/fixtures/input_dual_tilt_96_cell_array_1.tsv', 'r', newline='') as csv_file:
            csv_content = csv_file.read()
        self.site.cad_file = csv_content
        self.subject = Calculator(self.values)

        expected_link = [
            ['513833', 'TRAY, LINK, HELIX ROOF', '37'],
        ]
        expected_link_num = expected_link[0][2]

        bom = self.subject.compute_bom()
        links_in_bom = [elem[2] for elem in bom if elem[0] == '513833'][0]

        self.assertEqual(expected_link_num, links_in_bom)

    def test_array7(self):
        """
        Pivotal: 1544689
        """
        self.store = Store(mockredis.mock_redis_client(), "foo")
        self.site = Site()
        self.values = UserValues(self.store, self.site)
        self.site.building_height = 45
        self.site.building_width = 383
        self.site.building_length = 430
        self.site.parapet_height = 0.3
        self.site.wind_speed = 110
        self.site.exposure_category = ExposureCategory.C.value
        self.site.exposure_transition_distance = 1500
        self.site.module_type = ModuleType.Cell96.value
        self.site.ballast_block_weight = 14
        self.site.max_psf = 10
        self.site.anchor_type = AnchorType.OMG_PowerGrip_Plus.value
        self.site.spectral_response = 1.03

        self.site.system_type = SystemType.dualTilt.value
        with open('test/fixtures/input_dual_tilt_96_cell_array_7.tsv', 'r', newline='') as csv_file:
            csv_content = csv_file.read()
        self.site.cad_file = csv_content
        self.subject = Calculator(self.values)

        expected_link = [
            ['513833', 'TRAY, LINK, HELIX ROOF', '30'],
        ]
        expected_link_num = expected_link[0][2]

        bom = self.subject.compute_bom()
        links_in_bom = [elem[2] for elem in bom if elem[0] == '513833'][0]

        self.assertEqual(expected_link_num, links_in_bom)
