"""Graphical user interface for alarmclock."""

from __future__ import annotations

import argparse
import random
import sys
from dataclasses import dataclass
from datetime import datetime, timedelta, timezone
from functools import partial
from typing import TYPE_CHECKING

from PySide2.QtCore import QSize, Qt, QTime, QTimer
from PySide2.QtWidgets import (
    QApplication,
    QCheckBox,
    QDialog,
    QHBoxLayout,
    QLabel,
    QMainWindow,
    QPushButton,
    QTimeEdit,
    QVBoxLayout,
    QWidget,
)

from pytola.core.env import setup_pyside_env
from pytola.core.logger import get_logger
from pytola.core.themes import ThemeManager

setup_pyside_env()

logger = get_logger(__name__)

if TYPE_CHECKING:
    from PySide2.QtGui import QCloseEvent

__version__ = "0.1.3"
__build_date__ = "2026-01-22"


@dataclass
class AlarmClockConfig:
    """Configuration for the alarm clock application."""

    ALARM_CLOCK_TITLE: str = "Digital Alarm Clock"
    DIGITAL_FONT: str = "bold italic 81px 'Consolas'"
    DIGITAL_COLOR: str = "#ccee00"
    DIGITAL_BORDER_COLORS: tuple[str, ...] = (
        "#00aa00",
        "#eecc00",
        "#aa00aa",
        "#c0e0b0",
    )
    DIGITAL_TIMER_FORMAT: str = "%H:%M:%S"
    DIGITAL_UPDATE_INTERVAL: int = 1000

    BLINK_TITLE: str = "Alarm Reminder!"
    BLINK_CONTENT: str = "⏰ Time's Up!"
    BLINK_TYPE: str = "color"  # Options: 'color' or 'opacity'
    BLINK_BG_COLORS: tuple[str, ...] = (
        "#baf1ba",
        "#f8ccc3",
        "#aab4f0",
        "#efaec0",
    )
    BLINK_INTERVAL: int = 300  # ms
    DELAY_STEPS: tuple[int, ...] = (1, 5, 10, 15, 30, 60)  # minutes


config = AlarmClockConfig()


class DigitalClock(QLabel):
    """Cool digital clock display."""

    def __init__(self, parent: QWidget | None = None) -> None:
        super().__init__(parent)

        self.setAlignment(Qt.AlignCenter)

        self._color = config.DIGITAL_BORDER_COLORS[0]

        # Timer to update current time
        self._timer = QTimer()
        self._timer.timeout.connect(self.update_time)
        self._timer.start(config.DIGITAL_UPDATE_INTERVAL)  # Update every second

        self.update_time()

    def update_time(self) -> None:
        """Update current time display."""
        current = datetime.now(timezone.utc) + timedelta(hours=8)  # Beijing time
        self.setText(current.strftime(config.DIGITAL_TIMER_FORMAT))

        # Add blink effect
        self._color = random.choice([c for c in config.DIGITAL_BORDER_COLORS if c != self._color])
        self.setStyleSheet(f"""
            font: {config.DIGITAL_FONT};
            color: {config.DIGITAL_COLOR};
            background-color: black;
            border: 2px dashed {self._color};
            border-radius: 10px;
            padding: 10px;
        """)


class BlinkDialog(QDialog):
    """Alarm reminder dialog."""

    def __init__(self) -> None:
        super().__init__()

        self.setWindowTitle(config.BLINK_TITLE)
        self.setModal(True)
        self.setWindowFlags(
            self.windowFlags() | Qt.WindowStaysOnTopHint | Qt.WindowType.Dialog,
        )
        self.setFixedSize(QSize(400, 240))
        self.setWindowFlag(Qt.WindowCloseButtonHint, False)

        layout = QVBoxLayout()
        msg_label = QLabel(config.BLINK_CONTENT)
        msg_label.setStyleSheet("""
            color: red;
            font-size: 24px;
        """)
        msg_label.setAlignment(Qt.AlignmentFlag.AlignCenter)

        close_button = QPushButton("Close Alarm")
        close_button.clicked.connect(self.close_alarm)

        layout.addWidget(msg_label)
        layout.addWidget(close_button)
        self.setLayout(layout)

        # Blink control variables and timer
        self.blink_timer = QTimer(self)
        self.blink_timer.timeout.connect(self.update_blink)
        self.blink_state = False
        self.blink_type = config.BLINK_TYPE
        self.bg_color = random.choice(config.BLINK_BG_COLORS)
        self.blink_timer.start(config.BLINK_INTERVAL)

    def update_blink(self) -> None:
        """Timer timeout, update blink state."""
        if self.blink_type == "color":
            # Color blink logic
            colors = [c for c in config.BLINK_BG_COLORS if c != self.bg_color]
            new_color = random.choice(colors)
            self.setStyleSheet(f"background-color: {new_color}")
            self.bg_color = new_color
        elif self.blink_type == "opacity":
            new_opacity = 0.3 if self.blink_state else 1.0
            self.setWindowOpacity(new_opacity)

        self.blink_state = not self.blink_state  # Toggle state

    def close_alarm(self) -> None:
        """Close alarm dialog and stop blinking."""
        self.stop_blinking()
        self.accept()

    def stop_blinking(self) -> None:
        """Stop blinking."""
        self.blink_timer.stop()
        self.setWindowOpacity(1.0)  # Ensure opacity is restored

    def closeEvent(self, event: QCloseEvent) -> None:
        """Override close event, ensure timer stops."""
        self.stop_blinking()
        super().closeEvent(event)


class AlarmClock(QMainWindow):
    """Digital alarm clock GUI."""

    def __init__(self, theme: str = "modern_blue") -> None:
        super().__init__()
        self.setWindowTitle(f"{config.ALARM_CLOCK_TITLE} v{__version__}")

        # Store theme choice
        self.theme = theme

        # Create central widget
        central_widget = QWidget()
        self.setCentralWidget(central_widget)

        # Create layout
        main_layout = QVBoxLayout()
        main_layout.setSpacing(20)
        central_widget.setLayout(main_layout)

        # Cool digital clock display
        self.digital_clock = DigitalClock(parent=self)
        # Override digital clock style to maintain its distinctive appearance
        self.digital_clock.setStyleSheet(f"""
            font: {config.DIGITAL_FONT};
            color: {config.DIGITAL_COLOR};
            background-color: black;
            border: 2px dashed {config.DIGITAL_BORDER_COLORS[0]};
            border-radius: 10px;
            padding: 10px;
        """)
        main_layout.addWidget(self.digital_clock)

        # Alarm time setting
        time_layout = QHBoxLayout()
        time_label = QLabel("Alarm Time:")
        self.alarm_time_edit = QTimeEdit()
        self.alarm_time_edit.setDisplayFormat("HH:mm:ss")
        self.alarm_time_edit.setTime(
            QTime.currentTime().addSecs(config.DELAY_STEPS[0] * 60),
        )

        time_layout.addWidget(time_label)
        time_layout.addWidget(self.alarm_time_edit)
        main_layout.addLayout(time_layout)

        delay_layout = QHBoxLayout()
        delay_label = QLabel("Delay (min):")
        delay_layout.addWidget(delay_label)
        for minutes in config.DELAY_STEPS:
            button = QPushButton(str(minutes))
            button.clicked.connect(partial(self.set_delay, minutes))
            delay_layout.addWidget(button)
        main_layout.addLayout(delay_layout)

        # Repeat option
        self.repeat_checkbox = QCheckBox("Repeat")
        main_layout.addWidget(self.repeat_checkbox)

        # Control buttons
        button_layout = QHBoxLayout()
        self.set_alarm_button = QPushButton("Set Alarm")
        self.set_alarm_button.clicked.connect(self.set_alarm)
        self.cancel_alarm_button = QPushButton("Cancel Alarm")
        self.cancel_alarm_button.clicked.connect(self.cancel_alarm)
        self.cancel_alarm_button.setEnabled(False)
        button_layout.addWidget(self.set_alarm_button)
        button_layout.addWidget(self.cancel_alarm_button)
        main_layout.addLayout(button_layout)

        # Status display
        self.status_label = QLabel("Alarm not set")
        self.status_label.setAlignment(Qt.AlignCenter)
        main_layout.addWidget(self.status_label)

        # Center window on screen
        self.adjustSize()
        screen = QApplication.primaryScreen().geometry()
        x = (screen.width() - self.width()) // 2
        y = (screen.height() - self.height()) // 2
        self.move(x, y)

        # Alarm timer
        self.alarm_timer = QTimer()
        self.alarm_timer.timeout.connect(self.check_alarm)

        # Alarm state
        self.alarm_set = False
        self.alarm_time: QTime = QTime()  # Explicit type

    def set_delay(self, minutes: int) -> None:
        """Set delay alarm."""
        self.alarm_time_edit.setTime(
            QTime.currentTime().addSecs(minutes * 60),
        )

    def set_alarm(self) -> None:
        """Set alarm."""
        self.alarm_time = self.alarm_time_edit.time()
        self.alarm_set = True
        self.alarm_timer.start(1000)  # Check every second
        self.set_alarm_button.setEnabled(False)
        self.cancel_alarm_button.setEnabled(True)
        self.status_label.setText(
            f"Alarm set: {self.alarm_time.toString('HH:mm:ss')}",
        )

    def cancel_alarm(self) -> None:
        """Cancel alarm."""
        self.alarm_set = False
        self.alarm_timer.stop()
        self.set_alarm_button.setEnabled(True)
        self.cancel_alarm_button.setEnabled(False)
        self.status_label.setText("Alarm cancelled")

    def check_alarm(self) -> None:
        """Check if alarm time has arrived."""
        if not self.alarm_set:
            return

        current_time = QTime.currentTime()
        if (
            current_time.hour() == self.alarm_time.hour()
            and current_time.minute() == self.alarm_time.minute()
            and current_time.second() == self.alarm_time.second()
        ):
            # Show reminder message
            dialog = BlinkDialog()
            dialog.exec_()

            self.status_label.setText("⏰ Alarm Rang! ⏰")

            # Cancel alarm if not repeating
            if not self.repeat_checkbox.isChecked():
                self.cancel_alarm()

    def _restore_digital_clock_appearance(self) -> None:
        """恢复数字时钟的独特外观, 确保它不受主题更改影响."""
        # 重新设置数字时钟的样式, 保持其独特外观
        self.digital_clock.setStyleSheet(f"""
            font: {config.DIGITAL_FONT};
            color: {config.DIGITAL_COLOR};
            background-color: black;
            border: 2px dashed {config.DIGITAL_BORDER_COLORS[0]};
            border-radius: 10px;
            padding: 10px;
        """)


def parse_args() -> argparse.Namespace:
    """Parse command line arguments."""
    parser = argparse.ArgumentParser(description="Digital Alarm Clock")
    parser.add_argument(
        "--version",
        "-v",
        action="version",
        version=f"Digital Alarm Clock v{__version__}",
    )
    parser.add_argument(
        "--theme",
        "-t",
        default="modern_blue",
        # nargs="?",
        help="Set the theme (default: modern_blue)",
    )
    parser.add_argument("--debug", "-d", action="store_true", help="Enable debug mode")
    return parser.parse_args()


def main() -> None:
    """Run entry point for the GUI application.

    Gui utility tool
    """
    args = parse_args()

    if args.debug:
        logger.setLevel(logger.DEBUG)

    if not args.theme:
        logger.error("No theme provided. Exiting.")
        sys.exit(1)

    app = QApplication(sys.argv)
    ThemeManager.apply_theme(app, args.theme)
    window = AlarmClock(args.theme)
    window.show()
    sys.exit(app.exec_())
