from __future__ import annotations

import random
from datetime import datetime, timedelta, timezone
from functools import partial

from PySide2.QtCore import Qt, QTime, QTimer
from PySide2.QtGui import QCloseEvent, QMoveEvent, QResizeEvent
from PySide2.QtWidgets import (
    QDialog,
    QHBoxLayout,
    QLabel,
    QPushButton,
    QVBoxLayout,
    QWidget,
)
from pytola_core.config import ConfigMixin
from pytola_qtstyles import apply_theme

from .alarmclock_ui import Ui_AlarmClock

__version__ = "0.1.3"


class AlarmClockConfig(ConfigMixin):
    """Configuration for the alarm clock application."""

    WIN_SIZE = [480, 400]  # noqa: RUF012
    WIN_POS = [300, 200]  # noqa: RUF012
    THEME = "high_contrast"
    ALARM_CLOCK_TITLE = "Digital Alarm Clock"
    DIGITAL_FONT = "bold italic 81px 'Consolas'"
    DIGITAL_BORDER_COLORS = ("#00aa00", "#eecc00", "#aa00aa", "#c0e0b0")
    DIGITAL_TIMER_FORMAT = "%H:%M:%S"
    DIGITAL_UPDATE_INTERVAL = 1000

    BLINK_TITLE = "Alarm Reminder!"
    BLINK_CONTENT = "⏰ Time's Up!"
    BLINK_TYPE = "color"
    BLINK_BG_COLORS = ("#baf1ba", "#f8ccc3", "#aab4f0", "#efaec0")
    BLINK_INTERVAL = 300
    DELAY_STEPS = (1, 5, 10, 15, 30, 60)


conf = AlarmClockConfig()


class DigitalClock(QLabel):
    """数字时钟显示组件."""

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

        self.setAlignment(Qt.AlignCenter)
        self._color = conf.DIGITAL_BORDER_COLORS[0]
        self._timer = QTimer()
        self._timer.timeout.connect(self.update_time)
        self._timer.start(conf.DIGITAL_UPDATE_INTERVAL)
        self.update_time()

    def update_time(self) -> None:
        """更新当前时间显示并添加闪烁效果."""
        current = datetime.now(timezone.utc) + timedelta(hours=8)
        self.setText(current.strftime(conf.DIGITAL_TIMER_FORMAT))
        self._color = random.choice([c for c in conf.DIGITAL_BORDER_COLORS if c != self._color])  # noqa: S311
        self.setStyleSheet(
            f"font: {conf.DIGITAL_FONT}; color: white; background-color: black; "
            f"border: 2px dashed {self._color}; border-radius: 10px; padding: 10px;",
        )


class BlinkDialog(QDialog):
    """闹钟提醒对话框."""

    def __init__(self) -> None:
        super().__init__()
        self.setWindowTitle(conf.BLINK_TITLE)
        self.setModal(True)
        self.setWindowFlags(
            self.windowFlags() | Qt.WindowStaysOnTopHint | Qt.WindowType.Dialog,
        )
        self.setWindowFlag(Qt.WindowCloseButtonHint, on=False)
        self._setup_ui()
        self._start_blinking()

    def _setup_ui(self) -> None:
        """设置对话框 UI."""
        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_button.clicked.connect(self.close_alarm)

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

    def _start_blinking(self) -> None:
        """启动闪烁效果."""
        self.blink_timer = QTimer(self)
        self.blink_timer.timeout.connect(self.update_blink)
        self.blink_state = False
        self.bg_color = random.choice(conf.BLINK_BG_COLORS)  # noqa: S311
        self.blink_timer.start(conf.BLINK_INTERVAL)

    def update_blink(self) -> None:
        """更新闪烁状态."""
        if conf.BLINK_TYPE == "color":
            colors = [c for c in conf.BLINK_BG_COLORS if c != self.bg_color]
            self.bg_color = random.choice(colors)  # noqa: S311
            self.setStyleSheet(f"background-color: {self.bg_color}")
        else:
            self.setWindowOpacity(0.3 if self.blink_state else 1.0)

        self.blink_state = not self.blink_state

    def close_alarm(self) -> None:
        """关闭闹钟对话框."""
        self.stop_blinking()
        self.accept()

    def stop_blinking(self) -> None:
        """停止闪烁."""
        self.blink_timer.stop()
        self.setWindowOpacity(1.0)

    def closeEvent(self, event: QCloseEvent) -> None:  # type: ignore[override]
        """关闭窗口时确保定时器停止."""
        self.stop_blinking()
        super().closeEvent(event)


class AlarmClock(QWidget, Ui_AlarmClock):
    """数字闹钟 GUI 主窗口."""

    def __init__(self) -> None:
        super().__init__()
        self.setupUi(self)
        self.setGeometry(*conf.WIN_POS, *conf.WIN_SIZE)
        self.setWindowTitle(f"{conf.ALARM_CLOCK_TITLE} v{__version__}")
        self.status_label.setStyleSheet(
            "color: red; font-weight: bold; text-decoration: underline; font-style: italic;",
        )
        self.status_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.clock_label.setStyleSheet(
            f"font: {conf.DIGITAL_FONT}; background-color: black; "
            f"border: 2px dashed {conf.DIGITAL_BORDER_COLORS[0]}; border-radius: 10px; padding: 10px;",
        )
        self._init_clock()
        self._init_alarm()
        self._setup_delay_buttons()
        self.set_button.clicked.connect(self.on_toggle_alarm)
        self.alarm_timer.timeout.connect(self.on_check_alarm)

        self.resize(self.minimumSize())
        apply_theme(self, conf.THEME)

    def _init_clock(self) -> None:
        """初始化数字时钟."""
        digital_clock = DigitalClock(parent=self)
        digital_clock.setObjectName("clock_label")
        self.clock_label.deleteLater()
        self.clock_label = digital_clock
        self.verticalLayout_2.insertWidget(0, digital_clock, 1)
        self.alarm_time_spinbox.setDisplayFormat("HH:mm:ss")
        self.alarm_time_spinbox.setTime(
            QTime.currentTime().addSecs(conf.DELAY_STEPS[0] * 60),
        )

    def _init_alarm(self) -> None:
        """初始化闹钟相关组件和状态."""
        self.alarm_timer = QTimer()
        self.alarm_set = False
        self.alarm_time: QTime = QTime()
        self._alarm_triggered = False

    def _setup_delay_buttons(self) -> None:
        """设置延时按钮."""
        delay_layout = QHBoxLayout()
        delay_layout.addWidget(QLabel("延时 (分钟):"))
        for minutes in conf.DELAY_STEPS:
            button = QPushButton(str(minutes))
            button.clicked.connect(partial(self.set_delay, minutes))
            delay_layout.addWidget(button)
        reset_button = QPushButton("重置")
        reset_button.clicked.connect(self.reset_alarm_time)
        delay_layout.addWidget(reset_button)
        self.verticalLayout.insertLayout(1, delay_layout)

    def set_delay(self, minutes: int) -> None:
        """设置延时闹钟."""
        current_time = self.alarm_time_spinbox.time()
        new_time = current_time.addSecs(minutes * 60)
        self.alarm_time_spinbox.setTime(new_time)

    def reset_alarm_time(self) -> None:
        """重置闹钟时间为当前时间."""
        self.alarm_time_spinbox.setTime(QTime.currentTime())

    def on_toggle_alarm(self) -> None:
        """切换闹钟状态."""
        if self.alarm_set:
            self.alarm_set = False
            self.alarm_timer.stop()
            self.set_button.setText("设置闹钟")
            self.status_label.setText("闹钟已取消!")
            self._alarm_triggered = False
            return

        self.alarm_set = True
        self.set_button.setText("取消闹钟")
        self.alarm_time = self.alarm_time_spinbox.time()
        self.alarm_timer.start(1000)
        self.status_label.setText(f"闹钟已设置: {self.alarm_time.toString('HH:mm:ss')}")
        self._alarm_triggered = False

    def on_check_alarm(self) -> None:
        """检查是否到达闹钟时间."""
        if not self.alarm_set or self._alarm_triggered:
            return
        current_time = QTime.currentTime()
        secs_until_alarm = current_time.secsTo(self.alarm_time)
        if secs_until_alarm <= 0:
            self._alarm_triggered = True
            self.dialog = BlinkDialog()
            self.dialog.finished.connect(self.on_dialog_closed)
            self.dialog.show()
            self.status_label.setText("⏰ 闹钟响了! ⏰")

    def on_dialog_closed(self) -> None:
        """处理对话框关闭事件."""
        if not self.repeat_checkbox.isChecked():
            self.on_toggle_alarm()
            return
        self._alarm_triggered = False
        self.status_label.setText(f"下次响铃: {self.alarm_time.toString('HH:mm:ss')}")

    def moveEvent(self, event: QMoveEvent) -> None:
        """处理窗口移动事件."""
        super().moveEvent(event)
        conf.WIN_POS = [self.x(), self.y()]

    def resizeEvent(self, event: QResizeEvent) -> None:
        """处理窗口 resize 事件."""
        super().resizeEvent(event)
        conf.WIN_SIZE = [self.width(), self.height()]
