"""
통합 스케줄 화면 — 휴일 + 연차(예정/사용) + 반복 패턴.

기능:
    - 월별 캘린더 + 색상 코드 (휴일 빨강, 종일 연차 녹/파, 반차 노랑, 반반차 보라, 반복 회색)
    - 클릭한 날짜의 상세 (연차 추가/삭제, 휴일 정보, 매치되는 반복 패턴)
    - 반복 패턴 관리 → RecurringLeaveDialog
"""
from __future__ import annotations
from datetime import datetime, date, timedelta
from typing import List

from PyQt5.QtWidgets import (QDialog, QVBoxLayout, QHBoxLayout, QLabel,
                              QPushButton, QCalendarWidget, QListWidget,
                              QListWidgetItem, QMessageBox, QMenu,
                              QGroupBox, QSplitter, QWidget)
from PyQt5.QtCore import Qt, QDate
from PyQt5.QtGui import QTextCharFormat, QColor, QBrush

from core.recurring_leaves import expand_for_range, describe_pattern
from core.i18n import tr
from ui.styles import apply_dark_titlebar


# 색상 팔레트
_C_HOLIDAY = QColor("#e53935")          # 빨강
_C_LEAVE_FULL_PAST = QColor("#4caf50")  # 녹색 (사용)
_C_LEAVE_HALF_PAST = QColor("#ffc107")  # 노랑 (반차 사용)
_C_LEAVE_QUART_PAST = QColor("#9c27b0") # 보라 (반반차 사용)
_C_LEAVE_FULL_PLAN = QColor("#1976d2")  # 진한 파랑 (예정 종일)
_C_LEAVE_PART_PLAN = QColor("#64b5f6")  # 옅은 파랑 (예정 반차/반반차)
_C_RECURRING = QColor("#78909c")        # 회색 (반복 패턴 매치)
_C_TODAY = QColor("#ff9800")            # 주황 (오늘 강조 보더)


class ScheduleView(QDialog):
    """월간 통합 스케줄 다이얼로그."""

    def __init__(self, parent=None, db=None):
        super().__init__(parent)
        self.db = db
        self.setWindowTitle(tr('schedule.title'))
        self.setMinimumSize(820, 560)
        self._build_ui()
        self._reload()
        apply_dark_titlebar(self)

    def _build_ui(self):
        layout = QVBoxLayout()

        # 상단 툴바
        bar = QHBoxLayout()
        title = QLabel(tr('schedule.header'))
        title.setStyleSheet("font-weight: bold; font-size: 13px;")
        bar.addWidget(title)
        bar.addStretch()

        rec_btn = QPushButton(tr('schedule.btn_recurring'))
        rec_btn.clicked.connect(self._open_recurring_dialog)
        bar.addWidget(rec_btn)

        add_btn = QPushButton(tr('schedule.btn_add_leave'))
        add_btn.clicked.connect(self._open_add_leave_dialog)
        bar.addWidget(add_btn)

        layout.addLayout(bar)

        # 범례
        legend = QHBoxLayout()
        for label, color in [(tr('schedule.legend_holiday'), _C_HOLIDAY),
                              (tr('schedule.legend_leave_used'), _C_LEAVE_FULL_PAST),
                              (tr('schedule.legend_leave_planned'), _C_LEAVE_FULL_PLAN),
                              (tr('schedule.legend_half'), _C_LEAVE_HALF_PAST),
                              (tr('schedule.legend_recurring'), _C_RECURRING)]:
            sw = QLabel(f"  {label}  ")
            sw.setStyleSheet(
                f"background-color: {color.name()}; color: white; "
                f"padding: 2px 6px; border-radius: 3px;"
            )
            legend.addWidget(sw)
        legend.addStretch()
        layout.addLayout(legend)

        # 캘린더 + 상세 splitter
        splitter = QSplitter(Qt.Horizontal)

        # 좌측: 캘린더
        self.calendar = QCalendarWidget()
        self.calendar.setVerticalHeaderFormat(QCalendarWidget.NoVerticalHeader)
        self.calendar.clicked.connect(self._on_date_click)
        self.calendar.currentPageChanged.connect(self._on_page_change)
        splitter.addWidget(self.calendar)

        # 우측: 상세 패널
        right = QWidget()
        right_layout = QVBoxLayout()

        self.detail_title = QLabel(tr('schedule.detail_placeholder'))
        self.detail_title.setStyleSheet("font-weight: bold; font-size: 14px;")
        right_layout.addWidget(self.detail_title)

        self.detail_list = QListWidget()
        self.detail_list.setContextMenuPolicy(Qt.CustomContextMenu)
        self.detail_list.customContextMenuRequested.connect(self._on_list_menu)
        right_layout.addWidget(self.detail_list, 1)

        right.setLayout(right_layout)
        splitter.addWidget(right)
        splitter.setSizes([520, 280])

        layout.addWidget(splitter, 1)

        close_btn = QPushButton(tr('btn.close'))
        close_btn.clicked.connect(self.close)
        layout.addWidget(close_btn)

        self.setLayout(layout)

    # ------------------------------------------------------------- reload

    def _reload(self):
        """현재 화면 월에 대해 색상/리스트 갱신."""
        # 모든 날짜 포맷 초기화
        self.calendar.setDateTextFormat(QDate(), QTextCharFormat())

        y = self.calendar.yearShown()
        m = self.calendar.monthShown()
        # 한 달 + 양 옆 1주씩 (캘린더에 보이는 모든 날)
        first = date(y, m, 1)
        if m == 12:
            last = date(y + 1, 1, 1) - timedelta(days=1)
        else:
            last = date(y, m + 1, 1) - timedelta(days=1)
        view_start = first - timedelta(days=7)
        view_end = last + timedelta(days=7)

        # 휴일
        holidays = self.db.get_holidays_in_range(view_start.isoformat(),
                                                    view_end.isoformat()) \
                    if hasattr(self.db, 'get_holidays_in_range') else []
        if not holidays:
            holidays = self._fallback_holidays(view_start, view_end)

        for h in holidays:
            d = self._parse_date(h.get('date'))
            if d is None:
                continue
            self._paint(d, _C_HOLIDAY, fg='white')

        # 연차 (구체)
        leaves = self.db.get_leave_records_by_range(view_start.isoformat(),
                                                      view_end.isoformat())
        today = date.today()
        for r in leaves:
            d = self._parse_date(r.get('date'))
            if d is None:
                continue
            days = float(r.get('days') or 0)
            is_planned = d > today
            if is_planned:
                color = _C_LEAVE_FULL_PLAN if days >= 1.0 else _C_LEAVE_PART_PLAN
            else:
                if days >= 1.0:
                    color = _C_LEAVE_FULL_PAST
                elif days >= 0.5:
                    color = _C_LEAVE_HALF_PAST
                else:
                    color = _C_LEAVE_QUART_PAST
            self._paint(d, color, fg='white')

        # 반복 패턴 인스턴스
        recurring = self.db.get_recurring_leaves()
        for occ in expand_for_range(recurring, view_start, view_end):
            # 같은 날짜에 구체 leave가 있으면 그 색상이 우선 (덮어쓰지 않음)
            existing = self.calendar.dateTextFormat(
                QDate(occ.date.year, occ.date.month, occ.date.day))
            if existing.background() != QBrush():
                continue
            self._paint(occ.date, _C_RECURRING, fg='white')

    def _paint(self, d: date, color: QColor, fg: str = 'white'):
        qd = QDate(d.year, d.month, d.day)
        fmt = QTextCharFormat()
        fmt.setBackground(QBrush(color))
        fmt.setForeground(QBrush(QColor(fg)))
        self.calendar.setDateTextFormat(qd, fmt)

    # ------------------------------------------------------------- events

    def _on_date_click(self, qd: QDate):
        d = date(qd.year(), qd.month(), qd.day())
        date_str = d.isoformat()
        weekday_kr = [tr('label.weekday_mon'), tr('label.weekday_tue'), tr('label.weekday_wed'),
                      tr('label.weekday_thu'), tr('label.weekday_fri'), tr('label.weekday_sat'), tr('label.weekday_sun')]
        self.detail_title.setText(f"{date_str} ({weekday_kr[d.weekday()]}{tr('schedule.weekday_suffix')})")
        self.detail_list.clear()

        # 휴일
        holiday = self.db.get_holiday(date_str) if hasattr(self.db, 'get_holiday') else None
        if holiday:
            item = QListWidgetItem(tr('schedule.holiday', name=holiday.get('name', tr('label.holiday_default'))))
            item.setForeground(QBrush(QColor("#e53935")))
            self.detail_list.addItem(item)
        elif d.weekday() in (5, 6):
            item = QListWidgetItem(tr('schedule.weekend', weekday=weekday_kr[d.weekday()]))
            self.detail_list.addItem(item)

        # 연차 (구체)
        for r in self.db.get_leave_records_by_date(date_str):
            days = float(r.get('days') or 0)
            t = r.get('leave_type', '연차')
            memo = r.get('memo') or ''
            label = tr('schedule.leave_label', type=t, days=days)
            if memo:
                label += f" — {memo}"
            label += f" [id={r['id']}]"
            item = QListWidgetItem(label)
            item.setData(Qt.UserRole, ('concrete', r['id']))
            self.detail_list.addItem(item)

        # 반복 패턴 매치
        recurring = self.db.get_recurring_leaves(active_on=date_str)
        from core.recurring_leaves import expand_for_date
        for occ in expand_for_date(recurring, d):
            item = QListWidgetItem(
                tr('schedule.recurring_item', pattern=describe_pattern(occ.pattern),
                   days=occ.days, type=occ.leave_type)
            )
            item.setData(Qt.UserRole, ('recurring', occ.recurring_id))
            self.detail_list.addItem(item)

        if self.detail_list.count() == 0:
            self.detail_list.addItem(tr('schedule.no_events'))

    def _on_page_change(self, year: int, month: int):
        self._reload()

    def _on_list_menu(self, pos):
        item = self.detail_list.currentItem()
        if not item:
            return
        data = item.data(Qt.UserRole)
        if not data:
            return
        kind, _id = data
        menu = QMenu(self)
        del_act = menu.addAction(tr('schedule.delete'))
        chosen = menu.exec_(self.detail_list.viewport().mapToGlobal(pos))
        if chosen == del_act:
            self._delete_record(kind, _id)

    def _delete_record(self, kind: str, _id: int):
        if kind == 'concrete':
            reply = QMessageBox.question(
                self, tr('schedule.delete_leave_confirm_title'),
                tr('schedule.delete_leave_confirm_body'),
                QMessageBox.Yes | QMessageBox.No,
            )
            if reply == QMessageBox.Yes:
                self.db.delete_leave_record(_id)
                self._reload()
                # 상세 갱신
                d = self.calendar.selectedDate()
                self._on_date_click(d)
        elif kind == 'recurring':
            reply = QMessageBox.question(
                self, tr('schedule.delete_recurring_confirm_title'),
                tr('schedule.delete_recurring_confirm_body'),
                QMessageBox.Yes | QMessageBox.No,
            )
            if reply == QMessageBox.Yes:
                self.db.delete_recurring_leave(_id)
                self._reload()
                d = self.calendar.selectedDate()
                self._on_date_click(d)

    def _open_recurring_dialog(self):
        from ui.recurring_leave_dialog import RecurringLeaveDialog
        dlg = RecurringLeaveDialog(self, self.db)
        dlg.exec_()
        self._reload()

    def _open_add_leave_dialog(self):
        from ui.leave_view import AddLeaveDialog
        dlg = AddLeaveDialog(self, self.db)
        # 선택된 날짜로 기본값 설정
        d = self.calendar.selectedDate()
        if d.isValid():
            dlg.date_edit.setDate(d)
        if dlg.exec_() == dlg.Accepted:
            self._reload()
            self._on_date_click(d)

    # ------------------------------------------------------------- helpers

    @staticmethod
    def _parse_date(s):
        if not s:
            return None
        try:
            return datetime.strptime(s, '%Y-%m-%d').date()
        except (ValueError, TypeError):
            return None

    def _fallback_holidays(self, view_start: date, view_end: date) -> List[dict]:
        """get_holidays_in_range가 없는 경우 fallback (LIKE 쿼리)."""
        if not hasattr(self.db, 'get_holiday'):
            return []
        # 전체 공휴일을 조회하기엔 비싸서 캘린더에선 일자별 lazy lookup으로 대체
        # 여기서는 month start ~ end 범위만 매일 한 번씩 조회 (월 ~31회)
        out = []
        cur = view_start
        while cur <= view_end:
            h = self.db.get_holiday(cur.isoformat())
            if h:
                out.append(h)
            cur += timedelta(days=1)
        return out
