import json
import unittest

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

from helix.constants.module_type import ModuleType
from helix.constants.exposure_category import ExposureCategory
from helix.constants.inverter_type import InverterType
from helix.constants.module_type_constants.dual_tilt_96_cell_constants import DualTilt96CellConstants
from helix.constants.module_type_constants.single_tilt_96_cell_constants import SingleTilt96CellConstants
from helix.constants.panel_type import PanelType
from helix.constants.system_type import SystemType
from helix.constants.anchor_type import AnchorType
from helix.models.coordinate import Coordinate
from helix.models.panel import Panel
from helix.models.sql.inverters import Inverter
from helix.models.sql.power_monitors import PowerMonitor
from helix.models.sql.power_stations import PowerStation
from helix.models.sql.sites import Site
from helix.models.sql.standalone_inverters import StandaloneInverter
from helix.store import Store
from helix.user_values import UserValues


class UserValuesTest(unittest.TestCase):
    def setUp(self):
        self.site = Site(
            project_name='',
            building_height=0,
            building_width=0,
            building_length=0,
            parapet_height=0,
            wind_speed=0,
            exposure_category='C',
            exposure_transition_distance=0,
            ballast_block_weight=0,
            max_psf=0,
            system_type=SystemType.dualTilt.value,
            module_type=ModuleType.Cell96.value,
            anchor_type=AnchorType.OMG_PowerGrip_Plus.value,
            spectral_response=0,
            seismic_importance_factor=1,
        )

        self.store = Store(mockredis.mock_redis_client(), "foo")
        self.subject = UserValues(self.store, self.site)
        csv_file = open('test/fixtures/input_dual_tilt.csv', 'r')
        csv_contents = csv_file.read()
        csv_file.close()

        self.site.cad_file = csv_contents

    def test_project_name(self):
        eq_(self.subject.project_name(), '')
        self.site.project_name = '\t\n@_name'
        eq_(self.subject.project_name(), '\t\n@_name')

    def test_project_name_no_spaces(self):
        eq_(self.subject.project_name_no_spaces(), '')
        self.site.project_name = 'Test Project Name'
        eq_(self.subject.project_name_no_spaces(), 'test_project_name')

    def test_module_type(self):
        eq_(self.subject.module_type(), ModuleType.Cell96)
        self.site.module_type = ModuleType.Cell128.value
        eq_(self.subject.module_type(), ModuleType.Cell128)

    def test_building_height(self):
        eq_(self.subject.building_height(), 0)
        self.site.building_height = 20
        eq_(self.subject.building_height(), 20)

    def test_building_width(self):
        eq_(self.subject.building_width(), 0)
        self.site.building_width = 20
        eq_(self.subject.building_width(), 20)

    def test_building_length(self):
        eq_(self.subject.building_length(), 0)
        self.site.building_length = 20
        eq_(self.subject.building_length(), 20)

    def test_building_parapet_height(self):
        eq_(self.subject.building_parapet_height(), 0)
        self.site.parapet_height = 20
        eq_(self.subject.building_parapet_height(), 20)

    def test_exposure_category(self):
        eq_(self.subject.exposure_category(), ExposureCategory.C)
        self.site.exposure_category = "D"
        eq_(self.subject.exposure_category(), ExposureCategory.D)

    def test_exposure_category_interpolation(self):
        self.site.exposure_category = "B to C"
        self.site.exposure_transition_distance = 2000
        eq_(self.subject.exposure_category(), ExposureCategory.B_C)
        eq_(self.subject.exposure_category_transition_distance(), 2000)

    def test_wind_speed(self):
        eq_(self.subject.wind_speed(), 0.0)
        self.site.wind_speed = 20
        eq_(self.subject.wind_speed(), 20.0)

    def test_ballast_block_weight(self):
        eq_(self.subject.ballast_block_weight(), 0.0)
        self.site.ballast_block_weight = 20
        eq_(self.subject.ballast_block_weight(), 20.0)

    def test_max_allowable_system_pressure(self):
        eq_(self.subject.max_system_pressure(), 0)
        self.site.max_psf = 100.2
        eq_(self.subject.max_system_pressure(), 100.2)

    def test_system_type(self):
        eq_(self.subject.system_type(), SystemType.dualTilt)
        self.site.system_type = '0'
        eq_(self.subject.system_type(), SystemType.singleTilt)

    def test_module_system_constants(self):
        assert type(self.subject.module_system_constants()) is DualTilt96CellConstants
        self.site.system_type = '0'
        assert type(self.subject.module_system_constants()) is SingleTilt96CellConstants

    def test_anchor_type(self):
        eq_(self.subject.anchor_type(), AnchorType.OMG_PowerGrip_Plus)
        self.site.anchor_type = AnchorType.OMG_PowerGrip.value
        eq_(self.subject.anchor_type(), AnchorType.OMG_PowerGrip)

    def test_spectral_response(self):
        eq_(self.subject.spectral_response(), 0)
        self.site.spectral_response = 2.5
        eq_(self.subject.spectral_response(), 2.5)

    def test_importance_factor(self):
        eq_(self.subject.importance_factor(), 1)
        self.site.seismic_importance_factor = 1.5
        eq_(self.subject.importance_factor(), 1.5)

    def test_csv_parsing(self):
        parsed_csv = self.subject.csv()
        expected_result = [
            Panel(handle="'21EEE0", blockname="*U593", wind_zone=2, panel_type=PanelType.Corner, subarray=1, coordinate=Coordinate(0, 0, 0), original_coordinate=Coordinate(0, 0, 0)),
            Panel(handle="'21EECC", blockname="*U824", wind_zone=2, panel_type=PanelType.NorthSouth, subarray=1, coordinate=Coordinate(0, 0, 0), original_coordinate=Coordinate(0, 0, 0)),
            Panel(handle="'21EEB8", blockname="*U824", wind_zone=4, panel_type=PanelType.EastWest, subarray=1, coordinate=Coordinate(0, 0, 0), original_coordinate=Coordinate(0, 0, 0)),
            Panel(handle="'21EEA4", blockname="*U593", wind_zone=0, panel_type=PanelType.Corner, subarray=1, coordinate=Coordinate(0, 0, 0), original_coordinate=Coordinate(0, 0, 0)),
            Panel(handle="'21E940", blockname="*U171", wind_zone=1, panel_type=PanelType.Middle, subarray=1, coordinate=Coordinate(0, 0, 0), original_coordinate=Coordinate(0, 0, 0)),
            Panel(handle="'21E92C", blockname="*U824", wind_zone=3, panel_type=PanelType.Corner, subarray=1, coordinate=Coordinate(0, 0, 0), original_coordinate=Coordinate(0, 0, 0)),
            Panel(handle="'21E918", blockname="*U593", wind_zone=1, panel_type=PanelType.Corner, subarray=1, coordinate=Coordinate(0, 0, 0), original_coordinate=Coordinate(0, 0, 0))
        ]

        assert_array_equal(parsed_csv, expected_result)

    def test_csv_parsing_with_coordinates(self):
        csv_file = open('test/fixtures/input_dual_tilt_coordinates.csv', 'r')
        csv_contents = csv_file.read()
        csv_file.close()
        self.site.cad_file = csv_contents

        expected_result = [
            Panel(handle="'B247D", blockname="*U6006", wind_zone=0, panel_type=PanelType.Corner, subarray=1, coordinate=Coordinate(30043.319, -61598.761, rotation=2.534306), original_coordinate=Coordinate(30043.319, -61598.761, rotation=2.534306)),
            Panel(handle="'B245F", blockname="*U6006", wind_zone=0, panel_type=PanelType.NorthSouth, subarray=1, coordinate=Coordinate(29955.165, -61602.663, rotation=2.534306), original_coordinate=Coordinate(29955.165, -61602.663, rotation=2.534306)),
            Panel(handle="'B2441", blockname="*U6006", wind_zone=0, panel_type=PanelType.NorthSouth, subarray=1, coordinate=Coordinate(29867.012, -61606.565, rotation=2.534306), original_coordinate=Coordinate(29867.012, -61606.565, rotation=2.534306)),
            Panel(handle="'B2423", blockname="*U6006", wind_zone=0, panel_type=PanelType.Corner, subarray=1, coordinate=Coordinate(29778.858, -61610.467, rotation=2.534306), original_coordinate=Coordinate(29778.858, -61610.467, rotation=2.534306)),
            Panel(handle="'B2405", blockname="*U6006", wind_zone=0, panel_type=PanelType.EastWest, subarray=1, coordinate=Coordinate(30046.068, -61660.860, rotation=2.534306), original_coordinate=Coordinate(30046.068, -61660.860, rotation=2.534306)),
            Panel(handle="'B23E7", blockname="*U6006", wind_zone=0, panel_type=PanelType.Middle, subarray=1, coordinate=Coordinate(29957.914, -61664.762, rotation=2.534306), original_coordinate=Coordinate(29957.914, -61664.762, rotation=2.534306)),
            Panel(handle="'B23C9", blockname="*U6006", wind_zone=0, panel_type=PanelType.Middle, subarray=1, coordinate=Coordinate(29869.760, -61668.664, rotation=2.534306), original_coordinate=Coordinate(29869.760, -61668.664, rotation=2.534306)),
            Panel(handle="'B23AB", blockname="*U6006", wind_zone=0, panel_type=PanelType.EastWest, subarray=1, coordinate=Coordinate(29781.607, -61672.566, rotation=2.534306), original_coordinate=Coordinate(29781.607, -61672.566, rotation=2.534306)),
            Panel(handle="'B238D", blockname="*U6007", wind_zone=0, panel_type=PanelType.EastWest, subarray=1, coordinate=Coordinate(30048.816, -61722.960, rotation=2.534306), original_coordinate=Coordinate(30048.816, -61722.960, rotation=2.534306)),
            Panel(handle="'B236F", blockname="*U6007", wind_zone=0, panel_type=PanelType.Middle, subarray=1, coordinate=Coordinate(29960.663, -61726.861, rotation=2.534306), original_coordinate=Coordinate(29960.663, -61726.861, rotation=2.534306)),
            Panel(handle="'B2351", blockname="*U6007", wind_zone=0, panel_type=PanelType.Middle, subarray=1, coordinate=Coordinate(29872.509, -61730.763, rotation=2.534306), original_coordinate=Coordinate(29872.509, -61730.763, rotation=2.534306)),
            Panel(handle="'B2333", blockname="*U6007", wind_zone=0, panel_type=PanelType.EastWest, subarray=1, coordinate=Coordinate(29784.355, -61734.665, rotation=2.534306), original_coordinate=Coordinate(29784.355, -61734.665, rotation=2.534306)),
            Panel(handle="'B2315", blockname="*U6007", wind_zone=0, panel_type=PanelType.Corner, subarray=1, coordinate=Coordinate(30051.565, -61785.059, rotation=2.534306), original_coordinate=Coordinate(30051.565, -61785.059, rotation=2.534306)),
            Panel(handle="'B22F7", blockname="*U6007", wind_zone=0, panel_type=PanelType.NorthSouth, subarray=1, coordinate=Coordinate(29963.411, -61788.961, rotation=2.534306), original_coordinate=Coordinate(29963.411, -61788.961, rotation=2.534306)),
            Panel(handle="'B22D9", blockname="*U6007", wind_zone=0, panel_type=PanelType.NorthSouth, subarray=1, coordinate=Coordinate(29875.258, -61792.862, rotation=2.534306), original_coordinate=Coordinate(29875.258, -61792.862, rotation=2.534306)),
            Panel(handle="'B22B6", blockname="*U6007", wind_zone=0, panel_type=PanelType.Corner, subarray=1, coordinate=Coordinate(29787.104, -61796.764, rotation=2.534306), original_coordinate=Coordinate(29787.104, -61796.764, rotation=2.534306))
        ]

        parsed_csv = self.subject.csv()

        assert_array_equal(parsed_csv, expected_result)

    def test_csv_parsing_with_fuzzy_wind_zones(self):
        csv_file = open('test/fixtures/input_dual_tilt_coordinates_fuzzy_wind_zone.csv', 'r')
        csv_contents = csv_file.read()
        csv_file.close()
        self.site.cad_file = csv_contents

        expected_result = [
            Panel(handle="'B247D", blockname="*U6006", wind_zone=0, panel_type=PanelType.Corner, subarray=1,
                  coordinate=Coordinate(30043.319, -61598.761, rotation=2.534306),
                  original_coordinate=Coordinate(30043.319, -61598.761, rotation=2.534306), fuzzy_wind_zone=True),
            Panel(handle="'B245F", blockname="*U6006", wind_zone=0, panel_type=PanelType.NorthSouth, subarray=1,
                  coordinate=Coordinate(29955.165, -61602.663, rotation=2.534306),
                  original_coordinate=Coordinate(29955.165, -61602.663, rotation=2.534306), fuzzy_wind_zone=True),
            Panel(handle="'B2441", blockname="*U6006", wind_zone=0, panel_type=PanelType.NorthSouth, subarray=1,
                  coordinate=Coordinate(29867.012, -61606.565, rotation=2.534306),
                  original_coordinate=Coordinate(29867.012, -61606.565, rotation=2.534306), fuzzy_wind_zone=True),
            Panel(handle="'B2423", blockname="*U6006", wind_zone=0, panel_type=PanelType.Corner, subarray=1,
                  coordinate=Coordinate(29778.858, -61610.467, rotation=2.534306),
                  original_coordinate=Coordinate(29778.858, -61610.467, rotation=2.534306), fuzzy_wind_zone=True),
            Panel(handle="'B2405", blockname="*U6006", wind_zone=0, panel_type=PanelType.EastWest, subarray=1,
                  coordinate=Coordinate(30046.068, -61660.860, rotation=2.534306),
                  original_coordinate=Coordinate(30046.068, -61660.860, rotation=2.534306), fuzzy_wind_zone=True),
            Panel(handle="'B23E7", blockname="*U6006", wind_zone=0, panel_type=PanelType.Middle, subarray=1,
                  coordinate=Coordinate(29957.914, -61664.762, rotation=2.534306),
                  original_coordinate=Coordinate(29957.914, -61664.762, rotation=2.534306), fuzzy_wind_zone=True),
            Panel(handle="'B23C9", blockname="*U6006", wind_zone=0, panel_type=PanelType.Middle, subarray=1,
                  coordinate=Coordinate(29869.760, -61668.664, rotation=2.534306),
                  original_coordinate=Coordinate(29869.760, -61668.664, rotation=2.534306), fuzzy_wind_zone=False),
            Panel(handle="'B23AB", blockname="*U6006", wind_zone=0, panel_type=PanelType.EastWest, subarray=1,
                  coordinate=Coordinate(29781.607, -61672.566, rotation=2.534306),
                  original_coordinate=Coordinate(29781.607, -61672.566, rotation=2.534306), fuzzy_wind_zone=False),
            Panel(handle="'B238D", blockname="*U6007", wind_zone=0, panel_type=PanelType.EastWest, subarray=1,
                  coordinate=Coordinate(30048.816, -61722.960, rotation=2.534306),
                  original_coordinate=Coordinate(30048.816, -61722.960, rotation=2.534306), fuzzy_wind_zone=False),
            Panel(handle="'B236F", blockname="*U6007", wind_zone=0, panel_type=PanelType.Middle, subarray=1,
                  coordinate=Coordinate(29960.663, -61726.861, rotation=2.534306),
                  original_coordinate=Coordinate(29960.663, -61726.861, rotation=2.534306), fuzzy_wind_zone=True),
            Panel(handle="'B2351", blockname="*U6007", wind_zone=0, panel_type=PanelType.Middle, subarray=1,
                  coordinate=Coordinate(29872.509, -61730.763, rotation=2.534306),
                  original_coordinate=Coordinate(29872.509, -61730.763, rotation=2.534306), fuzzy_wind_zone=True),
            Panel(handle="'B2333", blockname="*U6007", wind_zone=0, panel_type=PanelType.EastWest, subarray=1,
                  coordinate=Coordinate(29784.355, -61734.665, rotation=2.534306),
                  original_coordinate=Coordinate(29784.355, -61734.665, rotation=2.534306), fuzzy_wind_zone=True),
            Panel(handle="'B2315", blockname="*U6007", wind_zone=0, panel_type=PanelType.Corner, subarray=1,
                  coordinate=Coordinate(30051.565, -61785.059, rotation=2.534306),
                  original_coordinate=Coordinate(30051.565, -61785.059, rotation=2.534306), fuzzy_wind_zone=True),
            Panel(handle="'B22F7", blockname="*U6007", wind_zone=0, panel_type=PanelType.NorthSouth, subarray=1,
                  coordinate=Coordinate(29963.411, -61788.961, rotation=2.534306),
                  original_coordinate=Coordinate(29963.411, -61788.961, rotation=2.534306), fuzzy_wind_zone=True),
            Panel(handle="'B22D9", blockname="*U6007", wind_zone=0, panel_type=PanelType.NorthSouth, subarray=1,
                  coordinate=Coordinate(29875.258, -61792.862, rotation=2.534306),
                  original_coordinate=Coordinate(29875.258, -61792.862, rotation=2.534306), fuzzy_wind_zone=True),
            Panel(handle="'B22B6", blockname="*U6007", wind_zone=0, panel_type=PanelType.Corner, subarray=1,
                  coordinate=Coordinate(29787.104, -61796.764, rotation=2.534306),
                  original_coordinate=Coordinate(29787.104, -61796.764, rotation=2.534306), fuzzy_wind_zone=True)
        ]

        parsed_csv = self.subject.csv()

        assert_array_equal(parsed_csv, expected_result)

    def test_power_stations_returns_sites_power_stations_formatted_nicely(self):
        self.site.power_stations = [
            PowerStation(
                quantity=1,
                ac_run_length=10,
                description='Test',
                id=30,
                inverters=[
                    Inverter(
                        model=str(InverterType.SMA.MODEL_12KW.value),
                        sunshade=True,
                        dc_switch=True,
                        strings_per_inverter=4
                    )
                ]
            )
        ]
        eq_(self.subject.power_stations(), [{
            'power_station_quantity': 1,
            'power_station_description': 'Test',
            'power_station_id': 30,
            'ac_run_length': 10,
            'inverter_quantity': 1,
            'inverters': [{
                'model': InverterType.SMA.MODEL_12KW,
                'strings_per_inverter': 4,
                'sunshade': True,
                'dc_switch': True,
                'splice_box': None,
            }],
        }])

    def test_standalone_inverters_returns_sites_standalone_inverters_formatted_nicely(self):
        self.site.standalone_inverters = [
            StandaloneInverter(
                id=1,
                site_id=self.site.id,
                ac_run_length=10,
                attachment_point_id=None,
                inverter=[
                    Inverter(
                        model=str(InverterType.SMA.MODEL_12KW.value),
                        sunshade=True,
                        dc_switch=True,
                        strings_per_inverter=4
                    )
                ]
            )
        ]
        eq_(self.subject.standalone_inverters(), [{
            'standalone_inverter_id': 1,
            'ac_run_length': 10,
            'attachment_point': ('Switch Gear', None),
            'model': InverterType.SMA.MODEL_12KW,
            'strings_per_inverter': 4,
            'sunshade': True,
            'dc_switch': True,
            'splice_box': None
        }])

    def test_power_monitors_returns_sites_power_monitors_formatted_nicely(self):
        self.site.power_monitors = [
            PowerMonitor(
                id=1,
                site_id=self.site.id,
                power_station_id=None)
        ]
        eq_(self.subject.power_monitors(), [{
            'monitor_id': 1,
            'power_source': ('Switch Gear/External', None)
        }])

    def test_get_user_provided_seismic_anchors(self):
        self.store.set("user_override_seismic_anchors", json.dumps([{"seismic_anchors": 3, 'panel_id': 2}, {"seismic_anchors": 0, 'panel_id': 4}]))
        eq_(self.subject.get_user_provided_seismic_anchors(), [
            Panel(id=2, seismic_anchors=3),
            Panel(id=4, seismic_anchors=0)
        ])
