import customtkinter as ctk
from datetime import datetime, timedelta, date
from view.theme import theme_manager
import calendar
from typing import Callable, Optional

try:
    import holidays  # type: ignore
except ImportError:
    holidays = None


class ModernCalendarPopup(ctk.CTkToplevel):
    """
    모던하고 심플한 커스텀 캘린더 팝업
    
    - 한국 공휴일 표시
    - 토요일(파란색), 일요일(빨간색) 구분
    - 오늘 날짜 강조
    - 범위 선택 시 색상 변경
    - 년/월 선택 드롭다운
    """
    
    def __init__(self, parent, start_date: date, end_date: date, callback: Optional[Callable]):
        super().__init__(parent)
        
        self.callback = callback
        self.start_date: date = start_date
        self.end_date: date = end_date
        self.temp_start: Optional[date] = None
        self.selecting_start = True
        
        # 현재 표시 중인 년/월
        self.current_year = datetime.now().year
        self.current_month = datetime.now().month
        
        # 한국 공휴일
        self.kr_holidays = holidays.KR(years=range(2020, 2030)) if holidays else set()
        
        # 팝업 설정
        self.title("기간 선택")
        self.geometry("420x600")  # 높이를 늘려서 6주 캘린더 수용
        self.resizable(False, False)
        self.attributes('-topmost', True)
        self.configure(fg_color=self._get_palette()["popup_bg"])
        
        # ESC 키로 닫기
        self.bind("<Escape>", lambda e: self.destroy())
        
        # 팝업 위치를 부모 버튼 아래로
        self._position_popup(parent)
        
        # UI 구성
        self._setup_ui()
        self._update_calendar()

    def _get_palette(self) -> dict:
        """현재 테마에 맞는 캘린더 색상 팔레트 반환"""
        is_dark = ctk.get_appearance_mode() == "Dark"

        if is_dark:
            return {
                "popup_bg": "#1f1f1f",
                "main_bg": "#1f1f1f",
                "day_bg": "#2b2b2b",
                "day_hover": "#3a3a3a",
                "normal_text": "#f1f1f1",
                "week_text": "#b8b8b8",
                "range_text": "#7db4ff",
                "today_bg": "#3d3314",
                "today_hover": "#52431a",
                "today_border": "#f4b400",
                "today_border_hover": "#f39c12",
                "range_edge_bg": "#1f538d",
                "range_mid_bg": "#2c3e50",
                "range_mid_hover": "#34495e",
                "neutral_btn": "#3a3a3a",
                "neutral_btn_hover": "#4a4a4a",
            }

        return {
            "popup_bg": "#f7f7f7",
            "main_bg": "#f7f7f7",
            "day_bg": "#ffffff",
            "day_hover": "#e9ecef",
            "normal_text": "#222222",
            "week_text": "#5f6368",
            "range_text": "#1f538d",
            "today_bg": "#fff3cd",
            "today_hover": "#ffe69c",
            "today_border": "#ffc107",
            "today_border_hover": "#ff9800",
            "range_edge_bg": "#1f538d",
            "range_mid_bg": "#d6eaf8",
            "range_mid_hover": "#aed6f1",
            "neutral_btn": "#e5e7eb",
            "neutral_btn_hover": "#d1d5db",
        }
    
    def _position_popup(self, parent):
        """팝업을 부모 위젯 아래에 위치"""
        self.update_idletasks()
        
        # 부모 위젯의 위치 가져오기
        x = parent.winfo_rootx()
        y = parent.winfo_rooty() + parent.winfo_height() + 5
        
        # 화면 경계 체크
        screen_width = self.winfo_screenwidth()
        screen_height = self.winfo_screenheight()
        
        if x + 420 > screen_width:
            x = screen_width - 420 - 10
        if y + 600 > screen_height:
            y = parent.winfo_rooty() - 600 - 5
        
        self.geometry(f"+{x}+{y}")
    
    def _setup_ui(self):
        """UI 구성"""
        palette = self._get_palette()

        main_frame = ctk.CTkFrame(self, fg_color=palette["main_bg"])
        main_frame.pack(fill="both", expand=True, padx=20, pady=20)
        
        # === 상단: 년/월 선택 ===
        header_frame = ctk.CTkFrame(main_frame, fg_color="transparent")
        header_frame.pack(fill="x", pady=(0, 15))
        
        # 이전 달 버튼
        self.prev_btn = ctk.CTkButton(
            header_frame,
            text="◀",
            width=40,
            height=35,
            command=self._prev_month,
            font=theme_manager.get_font(14),
            fg_color="transparent",
            hover_color=("gray85", "gray30")
        )
        self.prev_btn.pack(side="left", padx=5)
        
        # 년도 선택
        year_frame = ctk.CTkFrame(header_frame, fg_color="transparent")
        year_frame.pack(side="left", expand=True, fill="x", padx=5)
        
        years = [str(y) for y in range(2020, 2031)]
        self.year_combo = ctk.CTkComboBox(
            year_frame,
            values=years,
            width=90,
            height=35,
            command=self._on_year_changed,
            font=theme_manager.get_font(13, "bold"),
            dropdown_font=theme_manager.get_font(12),
            button_color=("gray70", "gray40"),
            border_color=("gray70", "gray40")
        )
        self.year_combo.set(str(self.current_year))
        self.year_combo.pack(side="left", padx=2)
        
        # 월 선택
        months = [f"{m}월" for m in range(1, 13)]
        self.month_combo = ctk.CTkComboBox(
            year_frame,
            values=months,
            width=80,
            height=35,
            command=self._on_month_changed,
            font=theme_manager.get_font(13, "bold"),
            dropdown_font=theme_manager.get_font(12),
            button_color=("gray70", "gray40"),
            border_color=("gray70", "gray40")
        )
        self.month_combo.set(f"{self.current_month}월")
        self.month_combo.pack(side="left", padx=2)
        
        # 다음 달 버튼
        self.next_btn = ctk.CTkButton(
            header_frame,
            text="▶",
            width=40,
            height=35,
            command=self._next_month,
            font=theme_manager.get_font(14),
            fg_color="transparent",
            hover_color=("gray85", "gray30")
        )
        self.next_btn.pack(side="left", padx=5)
        
        # === 선택된 범위 표시 ===
        self.range_label = ctk.CTkLabel(
            main_frame,
            text=f"{self.start_date.strftime('%Y-%m-%d')} ~ {self.end_date.strftime('%Y-%m-%d')}",
            font=theme_manager.get_font(12),
            text_color=palette["range_text"],
            height=30
        )
        self.range_label.pack(pady=(0, 10))
        
        # === 캘린더 그리드 (고정 높이) ===
        self.cal_frame = ctk.CTkFrame(main_frame, fg_color="transparent", height=330)  # 6주 + 헤더 고정
        self.cal_frame.pack(pady=10)
        self.cal_frame.pack_propagate(False)  # 크기 고정
        
        # 요일 헤더 (일요일부터 시작)
        weekdays = ["일", "월", "화", "수", "목", "금", "토"]
        colors = ["#e74c3c", palette["week_text"], palette["week_text"], palette["week_text"], palette["week_text"], palette["week_text"], "#3498db"]
        
        for i, (day, color) in enumerate(zip(weekdays, colors)):
            lbl = ctk.CTkLabel(
                self.cal_frame,
                text=day,
                width=50,
                height=30,
                font=theme_manager.get_font(12, "bold"),
                text_color=color
            )
            lbl.grid(row=0, column=i, padx=2, pady=2)
        
        # 날짜 버튼들을 저장할 리스트
        self.day_buttons = []
        
        # === 빠른 선택 버튼 ===
        quick_frame = ctk.CTkFrame(main_frame, fg_color="transparent")
        quick_frame.pack(pady=15, fill="x")
        
        quick_buttons = [
            ("오늘", 0),
            ("3일", 3),
            ("일주일", 7),
            ("한달", 30)
        ]
        
        for text, days in quick_buttons:
            btn = ctk.CTkButton(
                quick_frame,
                text=text,
                width=85,
                height=32,
                command=lambda d=days: self._quick_select(d),
                font=theme_manager.get_font(12),
                fg_color=palette["neutral_btn"],
                hover_color=palette["neutral_btn_hover"],
                corner_radius=6
            )
            btn.pack(side="left", padx=3, expand=True)
        
        # === 하단 버튼 ===
        btn_frame = ctk.CTkFrame(main_frame, fg_color="transparent")
        btn_frame.pack(pady=(10, 0), fill="x")
        
        confirm_btn = ctk.CTkButton(
            btn_frame,
            text="✓ 적용",
            height=38,
            command=self._apply,
            font=theme_manager.get_font(13, "bold"),
            fg_color=("#1f538d", "#2980b9"),
            hover_color=("#174a7a", "#1f6fa8"),
            corner_radius=8
        )
        confirm_btn.pack(side="left", padx=5, expand=True, fill="x")
        
        cancel_btn = ctk.CTkButton(
            btn_frame,
            text="✕ 취소",
            height=38,
            command=self.destroy,
            font=theme_manager.get_font(13),
            fg_color=palette["neutral_btn"],
            hover_color=palette["neutral_btn_hover"],
            corner_radius=8
        )
        cancel_btn.pack(side="left", padx=5, expand=True, fill="x")
    
    def _update_calendar(self):
        """캘린더 날짜 업데이트"""
        palette = self._get_palette()

        # 기존 버튼 제거
        for btn in self.day_buttons:
            btn.destroy()
        self.day_buttons.clear()
        
        # 해당 월의 첫날과 마지막날
        first_day = datetime(self.current_year, self.current_month, 1)
        last_day = datetime(self.current_year, self.current_month, 
                           calendar.monthrange(self.current_year, self.current_month)[1])
        
        # 첫 주의 시작 (일요일부터)
        start_weekday = (first_day.weekday() + 1) % 7  # 일요일=0
        
        # 오늘 날짜
        today = datetime.now().date()
        
        # 날짜 버튼 생성
        row = 1
        col = start_weekday
        
        for day in range(1, last_day.day + 1):
            current_date = datetime(self.current_year, self.current_month, day).date()
            
            # 요일 (0=일요일, 6=토요일)
            weekday = (first_day.replace(day=day).weekday() + 1) % 7
            
            # 기본 색상 설정
            if weekday == 0:  # 일요일
                text_color = "#e74c3c"
            elif weekday == 6:  # 토요일
                text_color = "#3498db"
            else:
                text_color = palette["normal_text"]
            
            # 공휴일 체크
            is_holiday = current_date in self.kr_holidays
            if is_holiday and weekday != 0:  # 일요일이 아닌 공휴일
                text_color = "#e74c3c"
            
            # 배경색 설정
            fg_color = palette["day_bg"]
            hover_color = palette["day_hover"]
            
            # 오늘 날짜 강조
            if current_date == today:
                fg_color = palette["today_bg"]
                hover_color = palette["today_hover"]
            
            # 범위 내 날짜 강조
            if self.start_date <= current_date <= self.end_date:
                if current_date == self.start_date or current_date == self.end_date:
                    fg_color = ("#1f538d", "#2980b9")
                    text_color = "white"
                    hover_color = ("#174a7a", "#1f6fa8")
                else:
                    fg_color = palette["range_mid_bg"]
                    hover_color = palette["range_mid_hover"]
            
            # 날짜 버튼 생성
            btn = ctk.CTkButton(
                self.cal_frame,
                text=str(day),
                width=50,
                height=45,
                command=lambda d=day: self._on_day_click(d),
                font=theme_manager.get_font(13),
                fg_color=fg_color,
                text_color=text_color,
                hover_color=hover_color,
                corner_radius=6,
                border_width=1 if current_date == today else 0,
                border_color=(palette["today_border"], palette["today_border_hover"])
            )
            btn.grid(row=row, column=col, padx=2, pady=2)
            self.day_buttons.append(btn)
            
            col += 1
            if col > 6:
                col = 0
                row += 1
    
    def _on_day_click(self, day):
        """날짜 클릭 이벤트"""
        selected_date = datetime(self.current_year, self.current_month, day).date()
        
        if self.selecting_start:
            self.temp_start = selected_date
            self.start_date = selected_date
            self.end_date = selected_date
            self.selecting_start = False
        else:
            if self.temp_start is None:
                self.temp_start = selected_date

            if selected_date < self.temp_start:
                self.start_date = selected_date
                self.end_date = self.temp_start
            else:
                self.start_date = self.temp_start
                self.end_date = selected_date
            self.selecting_start = True
        
        self._update_range_label()
        self._update_calendar()
    
    def _quick_select(self, days):
        """빠른 선택"""
        self.end_date = datetime.now().date()
        self.start_date = self.end_date - timedelta(days=days)
        self.selecting_start = True
        self.temp_start = None
        
        # 현재 월을 종료일 기준으로 변경
        self.current_year = self.end_date.year
        self.current_month = self.end_date.month
        self.year_combo.set(str(self.current_year))
        self.month_combo.set(f"{self.current_month}월")
        
        self._update_range_label()
        self._update_calendar()
    
    def _update_range_label(self):
        """범위 라벨 업데이트"""
        self.range_label.configure(
            text=f"{self.start_date.strftime('%Y-%m-%d')} ~ {self.end_date.strftime('%Y-%m-%d')}"
        )
    
    def _prev_month(self):
        """이전 달"""
        if self.current_month == 1:
            self.current_month = 12
            self.current_year -= 1
        else:
            self.current_month -= 1
        
        self.year_combo.set(str(self.current_year))
        self.month_combo.set(f"{self.current_month}월")
        self._update_calendar()
    
    def _next_month(self):
        """다음 달"""
        if self.current_month == 12:
            self.current_month = 1
            self.current_year += 1
        else:
            self.current_month += 1
        
        self.year_combo.set(str(self.current_year))
        self.month_combo.set(f"{self.current_month}월")
        self._update_calendar()
    
    def _on_year_changed(self, value):
        """년도 변경"""
        self.current_year = int(value)
        self._update_calendar()
    
    def _on_month_changed(self, value):
        """월 변경"""
        self.current_month = int(value.replace("월", ""))
        self._update_calendar()
    
    def _apply(self):
        """적용"""
        if self.callback:
            self.callback(self.start_date, self.end_date)
        self.destroy()


class DateRangeSelector(ctk.CTkFrame):
    """
    모던하고 심플한 날짜 범위 선택 컴포넌트
    """
    
    def __init__(self, parent, on_change_callback=None, **kwargs):
        super().__init__(parent, **kwargs)
        
        self.on_change_callback = on_change_callback
        self.popup: Optional[ModernCalendarPopup] = None
        
        # 기본값: 오늘부터 일주일 전
        self.end_date: date = datetime.now().date()
        self.start_date: date = self.end_date - timedelta(days=7)
        
        # UI 구성
        self._setup_ui()
        self._update_display()
    
    def _setup_ui(self):
        """UI 구성"""
        # 날짜 표시 버튼
        self.date_button = ctk.CTkButton(
            self,
            text="",
            width=250,
            height=40,
            command=self._show_popup,
            font=theme_manager.get_font(13),
            fg_color=("white", "gray20"),
            text_color=("gray20", "white"),
            hover_color=("gray90", "gray30"),
            border_width=2,
            border_color=("gray70", "gray40"),
            corner_radius=8
        )
        self.date_button.pack(side="left", padx=5)
        
        # 초기화 버튼
        self.reset_button = ctk.CTkButton(
            self,
            text="↻",
            width=40,
            height=40,
            command=self._reset_to_default,
            font=theme_manager.get_font(18),
            fg_color="transparent",
            text_color=("gray40", "gray60"),
            hover_color=("gray85", "gray30"),
            corner_radius=8
        )
        self.reset_button.pack(side="left", padx=2)
    
    def _update_display(self):
        """날짜 표시 업데이트"""
        if self.start_date == self.end_date:
            display_text = f"📅 {self.start_date.strftime('%Y-%m-%d')}"
        else:
            display_text = f"📅 {self.start_date.strftime('%m/%d')} ~ {self.end_date.strftime('%m/%d')}"
        
        self.date_button.configure(text=display_text)
    
    def _show_popup(self):
        """팝업 표시"""
        if self.popup and self.popup.winfo_exists():
            self.popup.focus_force()
            return
        
        self.popup = ModernCalendarPopup(
            self.date_button,
            self.start_date,
            self.end_date,
            self._on_date_selected
        )
    
    def _on_date_selected(self, start_date, end_date):
        """날짜 선택 콜백"""
        self.start_date = start_date
        self.end_date = end_date
        self._update_display()
        
        if self.on_change_callback:
            self.on_change_callback(self.start_date, self.end_date)
    
    def _reset_to_default(self):
        """기본값으로 초기화"""
        self.end_date = datetime.now().date()
        self.start_date = self.end_date - timedelta(days=7)
        self._update_display()
        
        if self.on_change_callback:
            self.on_change_callback(self.start_date, self.end_date)
    
    def get_date_range(self):
        """현재 선택된 날짜 범위 반환"""
        return self.start_date, self.end_date
