import os
import time
import textwrap


class StartupStatus:
    def __init__(self, title="INITIALISING"):
        self.title = title
        self._matrix = None
        self._canvas = None
        self._graphics = None
        self._font = None
        self._status_colour = None
        self._bar_colours = None
        self._splash_colour = None
        self._wifi_connected_colour = None
        self._wifi_configure_colour = None
        self._status_message = None
        self._status_started_at = None
        self._minimum_status_seconds = 2
        self._ready = False
        self._init_matrix()

    def _init_matrix(self):
        if os.environ.get("PLANE_TRACKER_NO_MATRIX"):
            return
        try:
            from rgbmatrix import RGBMatrix, RGBMatrixOptions, graphics
            from setup import fonts
            import config

            options = RGBMatrixOptions()
            options.hardware_mapping = "adafruit-hat-pwm" if config.HAT_PWM_ENABLED else "adafruit-hat"
            options.rows = 32
            options.cols = 64
            options.chain_length = max(1, min(2, int(config.PANEL_COUNT or 2)))
            options.parallel = 1
            options.row_address_type = 0
            options.multiplexing = 0
            options.pwm_bits = 11
            options.pwm_lsb_nanoseconds = 160
            options.led_rgb_sequence = "RGB"
            options.pixel_mapper_config = ""
            options.show_refresh_rate = 0
            options.gpio_slowdown = config.GPIO_SLOWDOWN
            options.brightness = config.BRIGHTNESS
            options.disable_hardware_pulsing = True
            options.drop_privileges = False
            options.limit_refresh_rate_hz = 120
            self._matrix = RGBMatrix(options=options)
            self._canvas = self._matrix.CreateFrameCanvas()
            self._graphics = graphics
            self._font = fonts.extrasmall
            self._status_colour = graphics.Color(0, 32, 91)
            self._bar_colours = (
                graphics.Color(183, 201, 211),
                graphics.Color(99, 153, 174),
                graphics.Color(0, 133, 173),
                graphics.Color(0, 85, 135),
                graphics.Color(0, 32, 91),
            )
            self._splash_colour = graphics.Color(0, 32, 91)
            self._wifi_connected_colour = graphics.Color(66, 95, 0)
            self._wifi_configure_colour = graphics.Color(114, 0, 22)
            self._ready = True
        except Exception as exc:
            print(f"[StartupDisplay] RGB matrix initialisation failed: {exc}")
            self._ready = False

    def _status_lines(self, message):
        message = str(message or "").strip().upper()
        layouts = {
            "STARTING": ("INITIALISING", "STARTING"),
            "STARTING DISPLAY": ("INITIALISING", "STARTING", "DISPLAY"),
            "CHECKING FOR UPDATES": ("CHECKING FOR", "UPDATES"),
            "DOWNLOADING UPDATE": ("DOWNLOADING", "UPDATE"),
            "VERIFYING UPDATE": ("VERIFYING", "UPDATE"),
            "EXTRACTING UPDATE": ("EXTRACTING", "UPDATE"),
            "BACKING UP CURRENT CODE": ("BACKING UP", "CURRENT CODE"),
            "INSTALLING UPDATE": ("INSTALLING", "UPDATE"),
            "UPDATE INSTALLED": ("UPDATE", "INSTALLED"),
            "RESTARTING UPDATED APP": ("RESTARTING", "UPDATED APP"),
        }
        if message in layouts:
            return layouts[message]

        wrapped = textwrap.wrap(
            message,
            width=16,
            break_long_words=True,
            break_on_hyphens=False,
        ) or [self.title.upper()]
        return tuple(wrapped[:3])

    def _progress_colour(self, percent):
        if percent <= 20:
            return self._bar_colours[0]
        if percent <= 40:
            return self._bar_colours[1]
        if percent <= 60:
            return self._bar_colours[2]
        if percent <= 80:
            return self._bar_colours[3]
        return self._bar_colours[4]

    def _finish_status_delay(self):
        if self._status_started_at is None:
            return
        elapsed = time.monotonic() - self._status_started_at
        remaining = self._minimum_status_seconds - elapsed
        if remaining > 0:
            time.sleep(remaining)

    def show(self, message, percent=None):
        text = f"{self.title}: {message}"
        if percent is not None:
            text += f" {int(percent)}%"
        print(text)
        if not self._ready:
            return

        status_message = str(message or "").strip().upper()
        if self._status_message is not None and status_message != self._status_message:
            self._finish_status_delay()

        width = self._canvas.width
        self._canvas.Clear()
        lines = self._status_lines(message)
        content_height = 28 if percent is not None else self._canvas.height
        line_height = 7
        first_baseline = ((content_height - (line_height * len(lines))) // 2) + 6
        for index, line in enumerate(lines):
            text_width = len(line) * 4
            x = max(0, (width - text_width) // 2)
            y = first_baseline + (index * line_height)
            self._graphics.DrawText(
                self._canvas,
                self._font,
                x,
                y,
                self._status_colour,
                line,
            )
        if percent is not None:
            pct = max(0, min(100, int(percent)))
            bar_width = max(0, int(width * pct / 100))
            bar_colour = self._progress_colour(pct)
            for x in range(bar_width):
                for y in (30, 31):
                    self._canvas.SetPixel(
                        x,
                        y,
                        bar_colour.red,
                        bar_colour.green,
                        bar_colour.blue,
                    )
        self._canvas = self._matrix.SwapOnVSync(self._canvas)
        if status_message != self._status_message:
            self._status_message = status_message
            self._status_started_at = time.monotonic()

    def _show_centered(self, lines, colour):
        if not self._ready:
            return

        width = self._canvas.width
        line_height = 8
        first_baseline = ((self._canvas.height - (line_height * len(lines))) // 2) + 6
        self._canvas.Clear()
        for index, line in enumerate(lines):
            text_width = len(line) * 4
            x = max(0, (width - text_width) // 2)
            y = first_baseline + (index * line_height)
            self._graphics.DrawText(self._canvas, self._font, x, y, colour, line)
        self._canvas = self._matrix.SwapOnVSync(self._canvas)

    def show_splash(self, seconds=5):
        print("PLANESINTHECLOUDS.COM")
        self._show_centered(("PLANESINTHE", "CLOUDS.COM"), self._splash_colour)
        time.sleep(max(0, seconds))

    def show_wifi_configure(self):
        print("CONFIGURE WIFI")
        self._show_centered(("CONFIGURE WIFI",), self._wifi_configure_colour)

    def show_wifi_connected(self, ip_address, seconds=5):
        ip_address = str(ip_address or "IP UNAVAILABLE")
        print(f"WIFI CONNECTED: {ip_address}")
        self._show_centered(("WIFI CONNECTED", ip_address), self._wifi_connected_colour)
        time.sleep(max(0, seconds))

    def close(self, clear=True):
        if self._ready:
            self._finish_status_delay()
            if clear:
                self._canvas.Clear()
                self._canvas = self._matrix.SwapOnVSync(self._canvas)
