import unittest
from PIL import Image
from io import BytesIO
import mockredis
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.coordinate import Coordinate
from helix.models.panel import Panel
from helix.models.sql.sites import Site
from helix.models.subarray import Subarray
from helix.presenters.image_presenter import ImagePresenter
from helix.store import Store
from helix.user_values import UserValues
from test.fixtures.sample_image_presented_panel_data import panels_pseries_single_tilt, subarrays_pseries_single_tilt
from test.test_helpers import assert_image_equal


class ImagePresenterTest(unittest.TestCase):
    def test_generate_image_taller_than_is_wide(self):
        # This is input_dual_tilt_128_crafted.tsv
        # With inputs as:
        # System Type: Dual-Tilt
        # Module Type: 128 Cell
        # Building Height: 100.0
        # Building Width: 50.0
        # Building Length: 100.0
        # Parapet Height: 0.0
        # Wind Speed: 110
        # Exposure Category: C
        # Ballast Block Weight: 14.0
        # Max Allowable System Pressure: 10.0
        # Anchor Type: OMG PowerGrip Plus
        # S_DS: 1.0
        panels = [
            Panel(wind_zone=3, subarray=1, coordinate=Coordinate(0, 0), ballast=20, wind_anchors=0, seismic_anchors=0),
            Panel(wind_zone=3, subarray=1, coordinate=Coordinate(0, 1), ballast=0,  wind_anchors=0, seismic_anchors=1),

            Panel(wind_zone=2, subarray=2, coordinate=Coordinate(0, 0), ballast=8,  wind_anchors=1, seismic_anchors=0),
            Panel(wind_zone=2, subarray=2, coordinate=Coordinate(1, 0), ballast=0,  wind_anchors=1, seismic_anchors=1),
            Panel(wind_zone=2, subarray=2, coordinate=Coordinate(0, 1), ballast=0,  wind_anchors=1, seismic_anchors=1),
            Panel(wind_zone=2, subarray=2, coordinate=Coordinate(1, 1), ballast=0,  wind_anchors=1, seismic_anchors=1)
        ]

        subarrays = [
            Subarray(subarray_number=1, origin=Coordinate(0, 0), start_row=0, size=2),
            Subarray(subarray_number=2, origin=Coordinate(0, 2), start_row=2, size=4)
        ]

        expected_image = Image.open("test/fixtures/images/expected_dual_tilt_pseries_image.png")
        received_bytes = ImagePresenter(SystemType.dualTilt, ModuleType.Cell128).generate_image(panels, subarrays)

        received_image = Image.open(BytesIO(received_bytes))

        assert_image_equal(received_image, expected_image, error=0.001)

    def test_generate_image_wider_than_is_tall(self):
        # This is input_single_tilt_pseries_coordinates.tsv
        # With inputs as:
        # System Type: Single-Tilt
        # Module Type: P-Series
        # Building Height: 100.0
        # Building Width: 100.0
        # Building Length: 100.0
        # Parapet Height: 1.0
        # Wind Speed: 100
        # Exposure Category: C
        # Ballast Block Weight: 14.0
        # Max Allowable System Pressure: 12.0
        # Anchor Type: OMG PowerGrip Plus
        # S_DS: 1.0
        panels = panels_pseries_single_tilt
        subarrays = subarrays_pseries_single_tilt

        expected_image = Image.open("test/fixtures/images/expected_single_tilt_pseries_image.png")
        received_bytes = ImagePresenter(SystemType.singleTilt, ModuleType.PSeries).generate_image(panels, subarrays)

        received_image = Image.open(BytesIO(received_bytes))

        assert_image_equal(received_image, expected_image, error=0.5)

    def test_return_image_stating_system_too_large_if_more_than_3000_panels_submitted(self):
        panels = [Panel() for _ in range(3000)]
        subarrays = []

        expected_image = Image.open("test/fixtures/images/expected_too_many_panels.png")
        received_bytes = ImagePresenter(SystemType.singleTilt, ModuleType.PSeries).generate_image(panels, subarrays)

        received_image = Image.open(BytesIO(received_bytes))

        assert_image_equal(received_image, expected_image, error=5e-2)
