from wtforms import StringField, SelectField, FormField, BooleanField
from wtforms.fields.html5 import IntegerField
from wtforms.validators import NumberRange, DataRequired

from helix.constants.inverter_brand import InverterBrand
from helix.constants.inverter_type import InverterType
from helix.constants.system_type import SystemType
from helix.forms.grouped_form import GroupedForm


def generate_string_choices(from_i, to_i, only_even=False):
    step = 2 if only_even else 1
    return list(
        map(lambda x: (x, "%s" % x), range(from_i, to_i + 1, step))
    )


class InverterBrandForm(GroupedForm):
    form_id = StringField(render_kw={'group': 'hidden', 'class': 'hidden', 'value': "inverter_brand_form"})
    inverter_brand_id = SelectField('',
                                    choices=[(InverterBrand.SMA.value, InverterBrand.SMA.label),
                                             (InverterBrand.DELTA.value, InverterBrand.DELTA.label)],
                                    coerce=int,
                                    default=InverterBrand.default_value(),
                                    render_kw={'group': 'inverter_brands'},
                                    )

    def populate_choices(self, inverter_brands):
        if len(inverter_brands) > 0:
            self.inverter_brand_id.default = next(
                map(lambda x: x['inverter_brand_id'], inverter_brands)
                , InverterBrand.default_value())
            self.process()

    def is_delta(self):
        return self.inverter_brand_id.data == InverterBrand.DELTA.value


class InverterFormSMA(GroupedForm):
    quantity = IntegerField('Quantity',
                            default=1,
                            render_kw={'group': 'quantity', 'row_class': 'quantity'},
                            validators=[NumberRange(0, None)])
    model = SelectField('Model',
                        choices=[(InverterType.SMA.MODEL_12KW.value, InverterType.SMA.MODEL_12KW.label),
                                 (InverterType.SMA.MODEL_15KW.value, InverterType.SMA.MODEL_15KW.label),
                                 (InverterType.SMA.MODEL_20KW.value, InverterType.SMA.MODEL_20KW.label),
                                 (InverterType.SMA.MODEL_24KW.value, InverterType.SMA.MODEL_24KW.label)],
                        coerce=int,
                        default=InverterType.SMA.default_value(),
                        render_kw={'group': 'non-optional', 'row_class': 'inverter_model'},
                        )
    strings_per_inverter = SelectField('# Strings/Inverter',
                                       coerce=int,
                                       choices=generate_string_choices(2, 8),
                                       default=8,
                                       render_kw={'group': 'non-optional', 'row_class': 'inverter_strings'})
    sunshade = BooleanField('Sun Shade', render_kw={'group': 'optional'})
    dc_switch = BooleanField('DC Switch', render_kw={'group': 'optional'})

    def update_strings(self, system_type):
        self.strings_per_inverter.choices = generate_string_choices(
            2,
            8,
            system_type != SystemType.singleTilt
        )


class InverterFormDelta(GroupedForm):
    quantity = IntegerField('Quantity',
                            default=1,
                            render_kw={'group': 'quantity', 'row_class': 'quantity'},
                            validators=[NumberRange(0, None)])
    model = SelectField('Model',
                        choices=[(InverterType.DELTA.MODEL_36KW.value, InverterType.DELTA.MODEL_36KW.label),
                                 (InverterType.DELTA.MODEL_42KW.value, InverterType.DELTA.MODEL_42KW.label),
                                 (InverterType.DELTA.MODEL_60KW.value, InverterType.DELTA.MODEL_60KW.label),
                                 # (InverterType.DELTA.MODEL_80KW.value, InverterType.DELTA.MODEL_80KW.label),
                                 ],
                        coerce=int,
                        default=InverterType.DELTA.default_value(),
                        render_kw={'group': 'non-optional', 'row_class': 'inverter_model'},
                        )
    strings_per_inverter = SelectField('# Strings/Inverter',
                                       coerce=int,
                                       choices=generate_string_choices(0, 24),
                                       default=8,
                                       render_kw={'group': 'non-optional', 'row_class': 'inverter_strings'})
    splice_box = BooleanField('Splice Box', default=True, render_kw={'group': 'optional'})


class EbomForm(GroupedForm):
    power_station_id = StringField(render_kw={'group': 'hidden', 'class': 'hidden'})
    form_id = StringField(render_kw={'group': 'hidden', 'class': 'hidden', 'value': 'power_station_form'})
    power_station_description = StringField('Power Station Description', render_kw={'group': 'header'},
                                            validators=[DataRequired(message='Power Station Description is required.')],
                                            default='Power Station 1')
    power_station_quantity = IntegerField('Power Station Quantity',
                                          default=1,
                                          validators=[NumberRange(0, None)],
                                          render_kw={'group': 'header'})
    ac_run_length = IntegerField('Total AC Run Length for Power Station(s) (ft)',
                                 render_kw={'group': 'header'}, default=0, validators=[NumberRange(0, None)])
    monitor_id = StringField(render_kw={'group': 'hidden', 'class': 'hidden'})

    inverter_quantity = SelectField('Inverters', choices=[(1, "1"), (2, "2"), (3, "3"), (4, "4")],
                                    coerce=int,
                                    default=4,
                                    render_kw={'group': 'inverter_quantity'})

    inverter_1 = FormField(InverterFormSMA, 'Inverter 1', render_kw={'group': 'inverters'})
    inverter_2 = FormField(InverterFormSMA, 'Inverter 2', render_kw={'group': 'inverters'})
    inverter_3 = FormField(InverterFormSMA, 'Inverter 3', render_kw={'group': 'inverters'})
    inverter_4 = FormField(InverterFormSMA, 'Inverter 4', render_kw={'group': 'inverters'})

    def update_inverter_strings_choices(self, system_type):
        self.inverter_1.update_strings(system_type)
        self.inverter_2.update_strings(system_type)
        self.inverter_3.update_strings(system_type)
        self.inverter_4.update_strings(system_type)


class StandAloneInverterForm(GroupedForm):
    standalone_inverter_id = StringField(render_kw={'group': 'hidden', 'class': 'hidden'})
    form_id = StringField(render_kw={'group': 'hidden', 'class': 'hidden', 'value': "standalone_inverter_form"})
    standalone_ac_run_length = IntegerField('AC Run Length for Inverter (ft)',
                                            render_kw={'group': 'power_station'},
                                            default=0, validators=[NumberRange(0, None)])

    def update_inverter_strings_choices(self, system_type):
        self.inverter.update_strings(system_type)

    def populate_choices(self):
        pass


class StandAloneInverterFormSMA(StandAloneInverterForm):
    inverter = FormField(InverterFormSMA, 'Inverter', render_kw={'group': 'inverters'})
    attachment_point = SelectField('Attachment Point',
                                   choices=[],
                                   default='switch_gear',
                                   render_kw={'group': 'power_station'})

    def populate_choices(self, power_stations, standalone_inverters):
        standalone_inverter_count_per_power_station = {}
        for inverter in standalone_inverters:
            key = inverter['attachment_point'][1]
            standalone_count = standalone_inverter_count_per_power_station.get(key) or 0
            standalone_inverter_count_per_power_station[key] = standalone_count + 1

        power_stations_with_free_slots = []
        for power_station in power_stations:
            standalone_count = standalone_inverter_count_per_power_station.get(power_station['power_station_id']) or 0
            inverter_count = power_station['inverter_quantity'] + standalone_count
            if inverter_count < 4 and power_station['power_station_quantity'] == 1:
                power_stations_with_free_slots.append(power_station)

        choices = map(lambda x: (str(x['power_station_id']), x['power_station_description']), power_stations_with_free_slots)
        self.attachment_point.choices = [('switch_gear', 'Switch Gear')] + list(choices)


class StandAloneInverterFormDelta(StandAloneInverterForm):
    inverter = FormField(InverterFormDelta, 'Inverter', render_kw={'group': 'inverters'})


class SupervisorForm(GroupedForm):
    monitor_id = StringField(render_kw={'group': 'hidden', 'class': 'hidden'})
    form_id = StringField(render_kw={'group': 'hidden', 'class': 'hidden', 'value': "supervisor_form"})
    power_source = SelectField('Power Source',
                               render_kw={'group': 'power_source'},
                               choices=[('switch_gear', 'Switch Gear/External')])


class SupervisorFormSMA(SupervisorForm):
    def populate_choices(self, power_stations, supervisors):
        supervisor_power_sources = list(map(lambda x: x['power_source'][1], supervisors))
        power_stations_without_supervisors = []
        for power_station in power_stations:
            if power_station['power_station_id'] not in supervisor_power_sources:
                power_stations_without_supervisors.append(power_station)

        choices = map(lambda x: (str(x['power_station_id']), x['power_station_description']), power_stations_without_supervisors)
        self.power_source.choices = self.power_source.choices[:1] + list(choices)
