from collections import namedtuple

SummaryValues = namedtuple('SummaryValues', ['total_weight', 'max_psf', 'avg_psf', 'anchors', 'ballast', 'max_weight', 'ballast_weight'])


class SummaryValuesCalculator(object):
    def __init__(self, user_values):
        self.values = user_values
        self.constants = self.values.module_system_constants()

    def summary_values(self, panels, subarrays, c_p_matrix, q_z, seismic_interval, ballast_calculator):
        summary_values = self.compute_summary(panels, subarrays, c_p_matrix, q_z, ballast_calculator)

        return [
            {'label': 'Total System Weight (lbs)', 'value': summary_values.total_weight},
            {'label': 'Max PSF', 'value': summary_values.max_psf},
            {'label': 'Avg PSF', 'value': summary_values.avg_psf},
            {'label': 'Total Anchors', 'value': summary_values.anchors},
            {'label': 'Total Ballast', 'value': summary_values.ballast},
            {'label': 'Max Possible System Weight', 'value': summary_values.max_weight},
            {'label': 'Max System Weight Ballast Block', 'value': summary_values.ballast_weight},
            {'label': 'Seismic Anchor Max. Spacing', 'value': seismic_interval}
        ]

    def documentation_summary_values(self, panels, subarrays, c_p_matrix, q_z, seismic_interval, ballast_calculator):
        summary_values = self.compute_summary(panels, subarrays, c_p_matrix, q_z, ballast_calculator)

        return {
            'total_system_weight': summary_values.total_weight,
            'max_psf': summary_values.max_psf,
            'ave_psf': summary_values.avg_psf,
            'total_anchors': summary_values.anchors,
            'total_ballast': summary_values.ballast,
            'max_possible_system_weight': summary_values.max_weight,
            'max_system_weight_ballast_block': summary_values.ballast_weight,
            'seismic_anchor_max_spacing': seismic_interval
        }

    def compute_summary(self, panels, subarrays, c_p_matrix, q_z, ballast_calculator):
        total_weight, avg_psf = self.system_weight_and_pressure(panels)

        max_psf = 0
        wind_anchors = 0
        total_ballast = 0
        for panel in panels:
            max_psf = panel.pressure if panel.pressure > max_psf else max_psf
            wind_anchors += panel.wind_anchors
            total_ballast += panel.ballast

        required_seismic_anchors = sum(subarray.required_seismic_anchors for subarray in subarrays)

        total_anchors = int(wind_anchors + required_seismic_anchors)

        max_weight, ballast_weight = self.find_max_system_weight(panels, c_p_matrix, q_z, ballast_calculator)

        return SummaryValues(
            total_weight=round(total_weight),
            max_psf=round(max_psf, 2),
            avg_psf=round(avg_psf, 2),
            anchors=total_anchors,
            ballast=int(total_ballast),
            max_weight=round(max_weight, 0),
            ballast_weight=ballast_weight
        )

    def system_weight_and_pressure(self, panels):
        constants = self.values.module_system_constants()
        effective_area = constants.surface_area / constants.ground_coverage_ratio

        psf_sum = sum(panel.pressure for panel in panels)
        return psf_sum * effective_area, psf_sum / len(panels)

    def find_max_system_weight(self, panels, c_p_matrix, q_z, ballast_calculator):
        copied_panels = list(panels)
        max_weight = 0
        ballast_block_weight_for_max_weight = 0
        for weight in range(12, 19):
            ballast_matrix = ballast_calculator.ballast_and_trays_matrix(c_p_matrix, q_z, copied_panels,
                                                                         ballast_block_weight=weight)

            total_weight, _ = self.system_weight_and_pressure(ballast_matrix)
            if total_weight > max_weight:
                max_weight = total_weight
                ballast_block_weight_for_max_weight = weight
        return max_weight, ballast_block_weight_for_max_weight
