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

from __future__ import annotations

import argparse
import logging
import random
import sys
from datetime import datetime, timedelta, timezone
from functools import partial

from PySide2.QtCore import QSize, Qt, QTime, QTimer
from PySide2.QtGui import QCloseEvent
from PySide2.QtWidgets import (
    QApplication,
    QCheckBox,
    QDialog,
    QHBoxLayout,
    QLabel,
    QMainWindow,
    QPushButton,
    QTimeEdit,
    QVBoxLayout,
    QWidget,
)
from pytola_core.config import ConfigMixin
from pytola_core.logger import get_logger
from pytola_qtstyles import apply_theme

logger = get_logger(__name__)


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


class AlarmClockConfig(ConfigMixin):
    """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)


conf = 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 = conf.DIGITAL_BORDER_COLORS[0]

        # Timer to update current time
        self._timer = QTimer()
        self._timer.timeout.connect(self.update_time)
        self._timer.start(conf.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(conf.DIGITAL_TIMER_FORMAT))

        # Add blink effect
        self._color = random.choice([c for c in conf.DIGITAL_BORDER_COLORS if c != self._color])
        self.setStyleSheet(f"""
            font: {conf.DIGITAL_FONT};
            color: {conf.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(conf.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(conf.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 = conf.BLINK_TYPE
        self.bg_color = random.choice(conf.BLINK_BG_COLORS)
        self.blink_timer.start(conf.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 conf.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:  # type: ignore[override]
        """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"{conf.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: {conf.DIGITAL_FONT};
            color: {conf.DIGITAL_COLOR};
            background-color: black;
            border: 2px dashed {conf.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(conf.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 conf.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.setStyleSheet(
            "color: red; font-weight: bold; text-decoration: underline; font-style: italic;"
        )
        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: {conf.DIGITAL_FONT};
            color: {conf.DIGITAL_COLOR};
            background-color: black;
            border: 2px dashed {conf.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="high_contrast", 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(logging.DEBUG)

    if not args.theme:
        logger.error("No theme provided. Exiting.")
        msg = "Theme argument is required"
        raise ValueError(msg)

    app = QApplication(sys.argv)

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