import re

from django.utils.translation import gettext_lazy as _
from wagtail.admin.forms.models import WagtailAdminModelForm

from .constants import MIN_ICON_WIDTH, MIN_SPLASH_WIDTH
from .utils import is_valid_bundle_id, is_valid_color, is_valid_relative_or_absolute_url


class MobileAppAdminForm(WagtailAdminModelForm):
    def clean(self):
        cleaned_data = super().clean()
        self._clean_colors(cleaned_data)
        self._clean_bundle_identifier(cleaned_data)
        self._clean_version_metadata(cleaned_data)
        self._clean_urls(cleaned_data)
        self._clean_images(cleaned_data)
        return cleaned_data

    def _clean_colors(self, cleaned_data):
        for field_name in [
            "theme_color",
            "background_color",
            "foreground_color",
            "accent_color",
            "status_bar_color",
            "navigation_bar_color",
        ]:
            if not is_valid_color(cleaned_data.get(field_name, "")):
                self.add_error(
                    field_name, _("Enter a valid hex color such as #0d6efd.")
                )

    def _clean_bundle_identifier(self, cleaned_data):
        app_id = cleaned_data.get("app_id", "")
        if app_id and not is_valid_bundle_id(app_id):
            self.add_error(
                "app_id",
                _(
                    "Enter a valid reverse-DNS bundle identifier such as com.mandelblog.client."
                ),
            )

    def _clean_version_metadata(self, cleaned_data):
        app_version = cleaned_data.get("app_version", "")
        if app_version and not re.fullmatch(
            r"[0-9]+(\.[0-9A-Za-z-]+){0,3}", app_version
        ):
            self.add_error(
                "app_version",
                _("Use a simple release version such as 1.0.0 or 2.1.0-beta1."),
            )
        build_number = cleaned_data.get("build_number")
        if build_number is not None and build_number < 1:
            self.add_error(
                "build_number",
                _("Build number must be 1 or higher."),
            )

    def _clean_urls(self, cleaned_data):
        for field_name in ["start_url", "scope", "offline_url"]:
            value = cleaned_data.get(field_name, "")
            if value and not is_valid_relative_or_absolute_url(value):
                self.add_error(
                    field_name,
                    _(
                        "Use either an absolute URL or a site-relative path starting with /."
                    ),
                )

    def _clean_images(self, cleaned_data):
        icon = cleaned_data.get("icon")
        splash_image = cleaned_data.get("splash_image")
        tablet = cleaned_data.get("tablet_screenshot")
        mobile = cleaned_data.get("mobile_screenshot")

        if icon:
            if icon.width != icon.height:
                self.add_error("icon", _("The app icon must be square."))
            if icon.width < MIN_ICON_WIDTH or icon.height < MIN_ICON_WIDTH:
                self.add_error(
                    "icon",
                    _("The app icon must be at least %(size)sx%(size)s pixels.")
                    % {"size": MIN_ICON_WIDTH},
                )

        if splash_image:
            if (
                splash_image.width < MIN_SPLASH_WIDTH
                or splash_image.height < MIN_SPLASH_WIDTH
            ):
                self.add_error(
                    "splash_image",
                    _("The splash image must be at least %(size)sx%(size)s pixels.")
                    % {"size": MIN_SPLASH_WIDTH},
                )

        for field_name, image in [
            ("tablet_screenshot", tablet),
            ("mobile_screenshot", mobile),
        ]:
            if image and (image.width < 320 or image.height < 320):
                self.add_error(
                    field_name,
                    _("Screenshots must be at least 320x320 pixels."),
                )
