from __future__ import annotations

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

import qdarkstyle
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,
)

__version__ = "0.1.2"
__build_date__ = "2025-09-16"


class AlarmClockConfig:
    """Alarm clock configuration."""

    ALARM_CLOCK_TITLE = "Digital Alarm Clock"

    DIGITAL_FONT: str = "bold italic 81px 'Consolas'"
    DIGITAL_COLOR: str = "#ccee00"
    DIGITAL_BORDER_COLORS: ClassVar[list[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: ClassVar[list[str]] = [
        "#baf1ba",
        "#f8ccc3",
        "#aab4f0",
        "#efaec0",
    ]
    BLINK_INTERVAL: ClassVar[int] = 300  # ms
    DELAY_STEPS: ClassVar[list[int]] = [1, 5, 10, 15, 30, 60]  # minutes


logging.basicConfig(level=logging.INFO, format="%(message)s")

conf = AlarmClockConfig()
logger = logging.getLogger(__name__)


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

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

        self.setAlignment(Qt.AlignCenter)  # type: ignore

        self._color = conf.DIGITAL_BORDER_COLORS[0]

        # Timer to update current time
        self._timer = QTimer()
        self._timer.timeout.connect(self.update_time)  # type: ignore
        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))
        logger.debug(f"Updated time: {current}")

        # Add blink effect
        self._color = random.choice(
            [_ for _ in conf.DIGITAL_BORDER_COLORS if _ != 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,  # type: ignore
        )
        self.setFixedSize(QSize(400, 240))

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

        close_button = QPushButton("Close Alarm")
        close_button.clicked.connect(self.accept)  # type: ignore

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

        # Prevent user from closing dialog by other means, ensure button click only
        self.setWindowFlag(Qt.WindowCloseButtonHint, False)  # type: ignore

        # Blink control variables and timer
        self.blink_timer = QTimer(self)
        self.blink_timer.timeout.connect(self.update_blink)  # type: ignore
        self.blink_state = False
        self.blink_type = conf.BLINK_TYPE

        # Initialize style
        self.bg_color = random.choice(conf.BLINK_BG_COLORS)
        self.origin_style = self.styleSheet()
        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 = [_ for _ in conf.BLINK_BG_COLORS[:] if _ != self.bg_color]
            self.setStyleSheet(f"background-color: {random.choice(colors)}")
        elif self.blink_type == "opacity":
            # Opacity blink logic - Note: Some systems may not fully support window 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 stop_blinking(self) -> None:
        """Stop blinking, restore original style."""
        self.blink_timer.stop()
        self.setStyleSheet(self.origin_style)  # Restore original style
        self.setWindowOpacity(1.0)  # Ensure opacity is restored

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


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

    def __init__(self) -> None:
        super().__init__()
        self.setWindowTitle(f"{conf.ALARM_CLOCK_TITLE} v{__version__}")
        self.setGeometry(
            QApplication.desktop().screenGeometry().center().x() - self.width() // 4,
            QApplication.desktop().screenGeometry().center().y() - self.height() // 2,
            self.width(),
            self.height(),
        )
        self.adjustSize()

        # Set window style
        self.setStyleSheet("""
            QMainWindow {
                background-color: #2b2b2b;
            }
            QLabel {
                color: #ffffff;
                font-size: 14px;
            }
            QPushButton {
                background-color: #3a3a3a;
                color: white;
                border: 1px solid #5a5a5a;
                padding: 8px;
                border-radius: 4px;
                font-size: 14px;
            }
            QPushButton:hover {
                background-color: #4a4a4a;
            }
            QPushButton:disabled {
                background-color: #2a2a2a;
                color: #6a6a6a;
            }
            QCheckBox {
                color: white;
                font-size: 14px;
            }
            QTimeEdit {
                background-color: #3a3a3a;
                color: white;
                border: 1px solid #5a5a5a;
                padding: 5px;
                font-size: 14px;
            }
        """)

        # 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)
        main_layout.addWidget(self.digital_clock)

        # Alarm time setting
        time_layout = QHBoxLayout()
        time_label = QLabel("Alarm Time:")
        time_label.setStyleSheet("color: white; font-size: 16px;")
        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_label.setStyleSheet("color: white; font-size: 16px;")
        delay_layout.addWidget(delay_label)
        for minutes in conf.DELAY_STEPS:
            button = QPushButton(str(minutes))
            button.setStyleSheet("color: white; font-size: 16px;")
            button.clicked.connect(partial(self.set_delay, minutes))  # type: ignore
            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)  # type: ignore
        self.cancel_alarm_button = QPushButton("Cancel Alarm")
        self.cancel_alarm_button.clicked.connect(self.cancel_alarm)  # type: ignore
        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)  # type: ignore
        self.status_label.setStyleSheet("color: #aaaaaa; font-size: 16px;")
        main_layout.addWidget(self.status_label)

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

        # 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')}",
        )
        self.status_label.setStyleSheet(
            "color: #00ff00; font-size: 16px; font-weight: bold;",
        )

    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")
        self.status_label.setStyleSheet("color: #aaaaaa; font-size: 16px;")

    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! ⏰")
            self.status_label.setStyleSheet(
                "color: #ff5555; font-size: 18px; font-weight: bold;",
            )

            # Add blink effect
            self.status_label.setStyleSheet("""
                color: #ff0000;
                font-size: 18px;
                font-weight: bold;
                background-color: #330000;
                border-radius: 5px;
                padding: 5px;
            """)

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


def main() -> None:
    parser = argparse.ArgumentParser(
        prog="alarmclock", description="Digital Alarm Clock"
    )
    parser.add_argument("-d", "--debug", action="store_true", help="Enable debug mode")
    parser.add_argument("-v", "--version", action="version", version=f"{__version__}")

    args = parser.parse_args()
    if args.debug:
        logger.setLevel(logging.DEBUG)

    app = QApplication(sys.argv)
    app.setStyleSheet(qdarkstyle.load_stylesheet_pyside2())
    window = AlarmClock()
    window.show()
    sys.exit(app.exec_())
