"""
SI UI Library - Splash Screen
Reusable animated splash screen with dark theme.

Usage:
    from si_ui import SplashScreen

    splash = SplashScreen(
        title="MY APP",
        subtitle="Description",
        gif_data=my_base64_gif_string,   # optional
    )
    splash.finished.connect(on_splash_done)
    splash.show()
"""

import base64

from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QLabel, QFrame, QGraphicsDropShadowEffect
from PyQt5.QtCore import Qt, QTimer, QByteArray, QBuffer, pyqtSignal
from PyQt5.QtGui import QColor, QMovie


class SplashScreen(QWidget):
    """Animated splash screen from embedded GIF data.

    Parameters
    ----------
    title : str
        Large heading text displayed below the animation.
    subtitle : str
        Smaller text displayed below the title.
    gif_data : str or None
        Base64-encoded GIF string.  When *None* a plain text fallback is shown
        and the splash auto-closes after *fallback_ms*.
    fallback_ms : int
        Milliseconds to show the text-only fallback (default 2000).
    timeout_ms : int
        Hard timeout – splash is closed regardless after this many ms (default 8000).
    accent_color : str
        CSS colour used for the title and border glow (default ``#89b4fa``).
    """

    finished = pyqtSignal()

    def __init__(
        self,
        title: str = "SI APPLICATION",
        subtitle: str = "",
        gif_data: str | None = None,
        fallback_ms: int = 2000,
        timeout_ms: int = 8000,
        accent_color: str = "#89b4fa",
        parent=None,
    ):
        super().__init__(parent)
        self._title_text = title
        self._subtitle_text = subtitle
        self._gif_data = gif_data
        self._fallback_ms = fallback_ms
        self._timeout_ms = timeout_ms
        self._accent = accent_color
        self.frame_count = 0
        self.total_frames = 0
        self._closed = False

        self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
        self.setAttribute(Qt.WA_TranslucentBackground)
        self._init_ui()

    # --------------------------------------------------------------------- #
    # UI
    # --------------------------------------------------------------------- #
    def _init_ui(self):
        layout = QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)

        # Container with dark background
        self.container = QFrame()
        self.container.setStyleSheet(f"""
            QFrame {{
                background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
                    stop:0 rgba(24, 24, 37, 245),
                    stop:1 rgba(30, 30, 46, 245));
                border: 1px solid rgba({self._hex_to_rgb_css(self._accent)}, 0.3);
                border-radius: 16px;
            }}
        """)

        container_layout = QVBoxLayout(self.container)
        container_layout.setContentsMargins(16, 16, 16, 16)
        container_layout.setSpacing(12)

        # GIF / fallback image
        self.gif_label = QLabel()
        self.gif_label.setAlignment(Qt.AlignCenter)

        if self._gif_data:
            try:
                gif_bytes = base64.b64decode(self._gif_data)
                self._byte_array = QByteArray(gif_bytes)
                self._buffer = QBuffer(self._byte_array)
                self._buffer.open(QBuffer.ReadOnly)

                self._movie = QMovie()
                self._movie.setDevice(self._buffer)
                self._movie.setCacheMode(QMovie.CacheAll)
                self._movie.frameChanged.connect(self._on_frame_changed)
                self.gif_label.setMovie(self._movie)

                self._movie.jumpToFrame(0)
                self.total_frames = self._movie.frameCount()
                size = self._movie.currentImage().size()
                if size.width() > 0 and size.height() > 0:
                    self.gif_label.setFixedSize(size.width(), size.height())
                else:
                    self.gif_label.setFixedSize(320, 440)

                self._movie.start()
            except Exception:
                self._setup_text_fallback()
        else:
            self._setup_text_fallback()

        container_layout.addWidget(self.gif_label, alignment=Qt.AlignCenter)

        # Title
        title_label = QLabel(self._title_text)
        title_label.setStyleSheet(f"""
            font-size: 16px;
            font-weight: bold;
            color: {self._accent};
            letter-spacing: 2px;
        """)
        title_label.setAlignment(Qt.AlignCenter)
        container_layout.addWidget(title_label)

        # Subtitle
        if self._subtitle_text:
            subtitle_label = QLabel(self._subtitle_text)
            subtitle_label.setStyleSheet("""
                font-size: 10px;
                color: rgba(205, 214, 244, 0.6);
                letter-spacing: 1px;
            """)
            subtitle_label.setAlignment(Qt.AlignCenter)
            container_layout.addWidget(subtitle_label)

        layout.addWidget(self.container)

        # Drop-shadow
        shadow = QGraphicsDropShadowEffect()
        shadow.setBlurRadius(40)
        shadow.setColor(QColor(0, 0, 0, 120))
        shadow.setOffset(0, 8)
        self.container.setGraphicsEffect(shadow)

        self.adjustSize()
        self._center_on_screen()

        # Hard timeout
        QTimer.singleShot(self._timeout_ms, self.close_splash)

    def _setup_text_fallback(self):
        """Show a text-only placeholder when no GIF is provided."""
        self.gif_label.setText(self._title_text[:2])
        self.gif_label.setStyleSheet(
            f"font-size: 48px; color: {self._accent}; font-weight: 300;"
        )
        self.gif_label.setFixedSize(320, 200)
        QTimer.singleShot(self._fallback_ms, self.close_splash)

    # --------------------------------------------------------------------- #
    # Animation tracking
    # --------------------------------------------------------------------- #
    def _on_frame_changed(self, frame_number: int):
        self.frame_count = frame_number
        if self.total_frames > 0 and frame_number >= self.total_frames - 1:
            QTimer.singleShot(500, self.close_splash)

    # --------------------------------------------------------------------- #
    # Close
    # --------------------------------------------------------------------- #
    def close_splash(self):
        if self._closed:
            return
        self._closed = True
        if hasattr(self, "_movie"):
            self._movie.stop()
        if hasattr(self, "_buffer"):
            self._buffer.close()
        self.finished.emit()
        self.close()

    # --------------------------------------------------------------------- #
    # Helpers
    # --------------------------------------------------------------------- #
    def _center_on_screen(self):
        screen = QApplication.primaryScreen().geometry()
        x = (screen.width() - self.width()) // 2
        y = (screen.height() - self.height()) // 2
        self.move(x, y)

    @staticmethod
    def _hex_to_rgb_css(hex_color: str) -> str:
        """Convert '#RRGGBB' to 'R, G, B' for use in rgba()."""
        h = hex_color.lstrip("#")
        return ", ".join(str(int(h[i : i + 2], 16)) for i in (0, 2, 4))

    # Click to dismiss
    def mousePressEvent(self, event):
        self.close_splash()
