import csv
import json

from helix.constants.anchor_type import AnchorType
from helix.constants.exposure_category import ExposureCategory
from helix.constants.module_type import ModuleType
from helix.constants.panel_type import PanelType
from helix.constants.system_type import SystemType
from helix.models.coordinate import Coordinate
from helix.models.panel import PanelData, Panel


class UserValues(object):
    def __init__(self, store, site):
        self.store = store
        self.site = site

    def project_name(self):
        return self.site.project_name

    def project_name_no_spaces(self):
        return "_".join(self.site.project_name.split()).lower()

    def building_height(self):
        return float(self.site.building_height)

    def building_width(self):
        return float(self.site.building_width)

    def building_length(self):
        return float(self.site.building_length)

    def building_parapet_height(self):
        return float(self.site.parapet_height)

    def module_type(self):
        return ModuleType(self.site.module_type)

    def exposure_category(self):
        return ExposureCategory(self.site.exposure_category)

    def exposure_category_transition_distance(self):
        return int(self.site.exposure_transition_distance or 0)

    def wind_speed(self):
        return float(self.site.wind_speed or 0)

    def ballast_block_weight(self):
        return float(self.site.ballast_block_weight)

    def module_system_constants(self):
        return self.system_type().module_constants(self.module_type())

    def power_stations(self):
        return [power_station.to_json() for power_station in self.site.power_stations]

    def standalone_inverters(self):
        return [standalone_inverter.to_json() for standalone_inverter in self.site.standalone_inverters]

    def power_monitors(self):
        return [power_monitor.to_json() for power_monitor in self.site.power_monitors]

    def inverter_brands(self):
        return [inverter_brands.to_json() for inverter_brands in self.site.inverter_brands]

    def csv(self):
        csv_data = self.site.cad_file
        if not csv_data:
            return None
        reader = csv.reader(csv_data.splitlines(), dialect='excel-tab')

        all_headers = next(reader)

        return [self.parse_csv_row(row, all_headers) for row in reader]

    def parse_csv_row(self, row, headers):
        wind_zone_indices = {
            "A": 0,
            "B": 1,
            "C": 2,
            "D": 3,
            "E": 4,
            "F": 5,
            "G": 6,
            "H": 7,
            "I": 8,
            "J": 9,
            "K": 10
        }
        wind_zone_index = headers.index(PanelData.WindZone.value)
        wind_zone = wind_zone_indices[row[wind_zone_index]]

        panel_type_index = headers.index(PanelData.PanelType.value)
        panel_type = PanelType.from_number(int(row[panel_type_index]))

        subarray_index = headers.index(PanelData.Subarray.value)
        subarray = int(row[subarray_index])

        try:
            xcoord_index = headers.index(PanelData.Xcoord.value)
            xcoord = float(row[xcoord_index])
        except:
            xcoord = 0

        try:
            ycoord_index = headers.index(PanelData.Ycoord.value)
            ycoord = float(row[ycoord_index])
        except:
            ycoord = 0

        try:
            rotation_index = headers.index(PanelData.Rotation.value)
            rotation = float(row[rotation_index])
        except:
            rotation = 0

        try:
            fuzzy_wind_zone_index = headers.index(PanelData.FuzzyWindZone.value)
            fuzzy_wind_zone = bool(int(row[fuzzy_wind_zone_index]))
        except:
            fuzzy_wind_zone = False

        coordinate = Coordinate(xcoord, ycoord, rotation=rotation)

        return Panel(handle=row[0], blockname=row[1], wind_zone=wind_zone, panel_type=panel_type, subarray=subarray,
                     coordinate=coordinate, original_coordinate=coordinate, fuzzy_wind_zone=fuzzy_wind_zone)

    def max_system_pressure(self):
        return float(self.site.max_psf)

    def system_type(self):
        return SystemType(self.site.system_type)

    def anchor_type(self):
        return AnchorType(self.site.anchor_type)

    def spectral_response(self):
        return float(self.site.spectral_response)

    def importance_factor(self):
        return float(self.site.seismic_importance_factor or 1)

    def user_override_seismic_anchors(self):
        return self.store.exists('user_override_seismic_anchors')

    def get_user_provided_seismic_anchors(self):
        data = json.loads(self.store.get('user_override_seismic_anchors').decode('utf-8'))
        return [Panel(id=x['panel_id'], seismic_anchors=x['seismic_anchors']) for x in data]

    def buildings_polygons(self):
        if self.store.exists('buildings_polygons'):
            return json.loads(self.store.get('buildings_polygons').decode('utf-8'))
        else:
            return []

    def is_panel_drawing_inaccurate(self):
        if self.store.exists('is_drawing_inaccurate'):
            return json.loads(self.store.get('is_drawing_inaccurate').decode('utf-8'))
        else:
            return False # should not happen, but if it does rather not show the warning

