import pygame
import sys
import datetime
import json
import os
from pygame.locals import *

# 初始化pygame
pygame.init()

# 颜色定义
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GRAY = (200, 200, 200)
LIGHT_GRAY = (240, 240, 240)
BLUE = (0, 120, 215)
LIGHT_BLUE = (173, 216, 230)
RED = (220, 0, 0)
GREEN = (0, 150, 0)
YELLOW = (255, 220, 0)
PURPLE = (128, 0, 128)
DARK_BLUE = (0, 0, 139)
ORANGE = (255, 165, 0)

# 窗口设置
WIDTH, HEIGHT = 1000, 700
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Calendar Reminder and Planner")

# 字体
try:
    # 尝试加载中文字体
    title_font = pygame.font.SysFont("simhei", 40)
    normal_font = pygame.font.SysFont("simhei", 30)
    small_font = pygame.font.SysFont("simhei", 24)
except:
    # 如果中文字体不可用，使用默认字体
    title_font = pygame.font.SysFont(None, 40)
    normal_font = pygame.font.SysFont(None, 30)
    small_font = pygame.font.SysFont(None, 24)

# 当前日期
current_date = datetime.date.today()
current_year = current_date.year
current_month = current_date.month
selected_date = current_date

# 数据存储
plans_file = "plans.json"
plans = {}

# 加载计划


def load_plans():
    global plans
    if os.path.exists(plans_file):
        try:
            with open(plans_file, 'r', encoding='utf-8') as f:
                plans = json.load(f)
        except:
            plans = {}
    else:
        plans = {}

# 保存计划


def save_plans():
    with open(plans_file, 'w', encoding='utf-8') as f:
        json.dump(plans, f, ensure_ascii=False, indent=2)


# 初始化数据
load_plans()

# 安全的日期格式化函数


def format_date(date_obj, format_str="%Y-%m-%d"):
    """安全的日期格式化函数，避免编码问题"""
    try:
        # 使用英文格式
        if format_str == "year_month":
            return f"{date_obj.year} {date_obj.month}"
        elif format_str == "full_date":
            return f"{date_obj.year}/{date_obj.month:02d}/{date_obj.day:02d}"
        elif format_str == "date_only":
            return f"{date_obj.month}/{date_obj.day}"
        elif format_str == "weekday":
            weekdays_en = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
            return weekdays_en[date_obj.weekday()]
        else:
            return date_obj.strftime(format_str)
    except:
        # 如果出错，使用简单的字符串格式化
        return f"{date_obj.year}/{date_obj.month:02d}/{date_obj.day:02d}"

# 输入框类


class InputBox:
    def __init__(self, x, y, w, h, text='', placeholder=''):
        self.rect = pygame.Rect(x, y, w, h)
        self.color = BLACK
        self.text = text
        self.placeholder = placeholder
        self.txt_surface = normal_font.render(text, True, self.color)
        self.active = False
        self.width = w
        self.max_length = 50  # 最大字符数

    def handle_event(self, event):
        if event.type == MOUSEBUTTONDOWN:
            # 如果点击了输入框
            if self.rect.collidepoint(event.pos):
                self.active = True
            else:
                self.active = False

        if event.type == KEYDOWN:
            if self.active:
                if event.key == K_RETURN:
                    return True
                elif event.key == K_BACKSPACE:
                    self.text = self.text[:-1]
                elif event.key == K_ESCAPE:
                    self.active = False
                else:
                    # 限制输入长度
                    if len(self.text) < self.max_length:
                        self.text += event.unicode

                # 重新渲染文本
                self.txt_surface = normal_font.render(
                    self.text, True, self.color)

        return False

    def draw(self, screen):
        # 绘制输入框
        pygame.draw.rect(screen, WHITE, self.rect, 0)
        pygame.draw.rect(screen, self.color, self.rect, 2)

        # 高亮显示活动输入框
        if self.active:
            pygame.draw.rect(screen, BLUE, self.rect, 3)

        # 绘制文本
        if self.text:
            screen.blit(self.txt_surface, (self.rect.x+5, self.rect.y+5))
        elif not self.text and not self.active:
            placeholder_surface = normal_font.render(
                self.placeholder, True, (150, 150, 150))
            screen.blit(placeholder_surface, (self.rect.x+5, self.rect.y+5))

        # 显示字符计数
        count_text = small_font.render(
            f"{len(self.text)}/{self.max_length}", True, GRAY)
        screen.blit(count_text, (self.rect.right - 50, self.rect.y + 5))

    def get_text(self):
        return self.text.strip()

    def clear(self):
        self.text = ''
        self.txt_surface = normal_font.render(self.text, True, self.color)

# 按钮类


class Button:
    def __init__(self, x, y, w, h, text, color=BLUE, hover_color=DARK_BLUE, text_color=WHITE):
        self.rect = pygame.Rect(x, y, w, h)
        self.text = text
        self.color = color
        self.hover_color = hover_color
        self.text_color = text_color
        self.current_color = color
        self.is_hovered = False

    def draw(self, screen):
        # 检查鼠标是否悬停
        mouse_pos = pygame.mouse.get_pos()
        self.is_hovered = self.rect.collidepoint(mouse_pos)
        self.current_color = self.hover_color if self.is_hovered else self.color

        # 绘制按钮
        pygame.draw.rect(screen, self.current_color,
                         self.rect, border_radius=5)
        pygame.draw.rect(screen, BLACK, self.rect, 2, border_radius=5)

        # 绘制按钮文字
        text_surface = normal_font.render(self.text, True, self.text_color)
        text_rect = text_surface.get_rect(center=self.rect.center)
        screen.blit(text_surface, text_rect)

        return self.is_hovered

    def is_clicked(self, event):
        if event.type == MOUSEBUTTONDOWN and event.button == 1:
            return self.rect.collidepoint(event.pos)
        return False

# 日历显示


def draw_calendar():
    # 绘制日历背景
    calendar_rect = pygame.Rect(20, 80, 500, 500)
    pygame.draw.rect(screen, WHITE, calendar_rect)
    pygame.draw.rect(screen, BLACK, calendar_rect, 2)

    # 绘制标题
    month_year_text = f"{current_year} {current_month}"
    title_text = title_font.render(month_year_text, True, BLUE)
    screen.blit(title_text, (calendar_rect.centerx -
                title_text.get_width()//2, 20))

    # 绘制星期标题背景
    weekdays_bg = pygame.Rect(
        calendar_rect.x, calendar_rect.y, calendar_rect.width, 40)
    pygame.draw.rect(screen, LIGHT_BLUE, weekdays_bg)

    # 绘制星期
    weekdays = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
    for i, day in enumerate(weekdays):
        day_color = RED if i == 6 else (BLUE if i == 5 else DARK_BLUE)
        day_text = normal_font.render(day, True, day_color)
        screen.blit(day_text, (calendar_rect.x +
                    20 + i*70, calendar_rect.y + 10))

    # 计算当月第一天是星期几
    first_day = datetime.date(current_year, current_month, 1)
    first_day_weekday = first_day.weekday()  # 周一为0

    # 计算当月天数
    if current_month == 12:
        next_month = datetime.date(current_year+1, 1, 1)
    else:
        next_month = datetime.date(current_year, current_month+1, 1)

    days_in_month = (next_month - first_day).days

    clicked_date = None

    # 绘制日期
    for day in range(1, days_in_month+1):
        date_obj = datetime.date(current_year, current_month, day)
        weekday = date_obj.weekday()

        x = calendar_rect.x + 20 + weekday * 70
        y = calendar_rect.y + 60 + ((day + first_day_weekday - 1) // 7) * 50

        # 绘制日期背景
        date_rect = pygame.Rect(x-5, y-5, 40, 40)

        # 如果是今天
        if date_obj == current_date:
            pygame.draw.rect(screen, LIGHT_BLUE, date_rect, border_radius=5)
            pygame.draw.rect(screen, BLUE, date_rect, 2, border_radius=5)
        # 如果是选中日期
        elif date_obj == selected_date:
            pygame.draw.rect(screen, YELLOW, date_rect, border_radius=5)
            pygame.draw.rect(screen, ORANGE, date_rect, 2, border_radius=5)
        # 如果有计划
        elif date_obj.isoformat() in plans:
            pygame.draw.rect(screen, GREEN, date_rect, border_radius=5)
        else:
            pygame.draw.rect(screen, LIGHT_GRAY, date_rect, border_radius=5)

        # 绘制日期数字
        date_color = RED if weekday == 6 else (BLACK if weekday < 5 else BLUE)
        date_text = normal_font.render(str(day), True, date_color)
        screen.blit(date_text, (x, y))

        # 如果有计划，显示小圆点
        date_str = date_obj.isoformat()
        if date_str in plans:
            pygame.draw.circle(screen, RED, (x+30, y+5), 4)

        # 处理日期点击
        mouse_pos = pygame.mouse.get_pos()
        if date_rect.collidepoint(mouse_pos):
            pygame.draw.rect(screen, BLACK, date_rect, 2, border_radius=5)

            # 显示日期信息
            date_display = f"{date_obj.month}/{date_obj.day}/{date_obj.year}"
            info_text = small_font.render(date_display, True, DARK_BLUE)
            pygame.draw.rect(
                screen, WHITE, (mouse_pos[0]+10, mouse_pos[1]-30, 120, 25))
            pygame.draw.rect(
                screen, BLACK, (mouse_pos[0]+10, mouse_pos[1]-30, 120, 25), 1)
            screen.blit(info_text, (mouse_pos[0]+15, mouse_pos[1]-25))

            # 检查点击
            mouse_pressed = pygame.mouse.get_pressed()
            if mouse_pressed[0]:
                clicked_date = date_obj

    return clicked_date if clicked_date else selected_date

# 绘制计划列表


def draw_plans():
    # 绘制计划区域背景
    plans_rect = pygame.Rect(540, 80, 440, 500)
    pygame.draw.rect(screen, WHITE, plans_rect)
    pygame.draw.rect(screen, BLACK, plans_rect, 2)

    # 绘制标题
    date_display = f"{selected_date.month}/{selected_date.day}/{selected_date.year}"
    title = title_font.render(f"Plans - {date_display}", True, BLUE)
    screen.blit(title, (plans_rect.centerx - title.get_width()//2, 20))

    # 显示计划数量
    date_key = selected_date.isoformat()
    plan_count = len(plans.get(date_key, []))
    count_text = small_font.render(f"Plans: {plan_count}", True, DARK_BLUE)
    screen.blit(count_text, (plans_rect.x + 10, plans_rect.y + 40))

    # 显示计划
    y_offset = plans_rect.y + 70
    delete_buttons = []  # 存储删除按钮

    if date_key in plans and plans[date_key]:
        for i, plan in enumerate(plans[date_key]):
            if y_offset > plans_rect.bottom - 50:
                break

            # 计划项背景
            plan_rect = pygame.Rect(plans_rect.x + 10, y_offset, 420, 40)
            color = LIGHT_BLUE if i % 2 == 0 else LIGHT_GRAY
            pygame.draw.rect(screen, color, plan_rect, border_radius=5)
            pygame.draw.rect(screen, GRAY, plan_rect, 1, border_radius=5)

            # 计划编号
            num_text = small_font.render(f"{i+1}.", True, BLUE)
            screen.blit(num_text, (plan_rect.x + 5, plan_rect.y + 10))

            # 计划内容
            display_text = plan[:35] + "..." if len(plan) > 35 else plan
            plan_text = small_font.render(display_text, True, BLACK)
            screen.blit(plan_text, (plan_rect.x + 30, plan_rect.y + 10))

            # 删除按钮
            delete_btn = Button(plan_rect.right - 30,
                                plan_rect.y + 5, 30, 30, "X", RED, (200, 0, 0))
            delete_btn.draw(screen)
            delete_buttons.append((delete_btn, i))

            y_offset += 50
    else:
        no_plans_text = normal_font.render("No plans for this day", True, GRAY)
        screen.blit(no_plans_text, (plans_rect.centerx -
                    no_plans_text.get_width()//2, plans_rect.centery))

    return y_offset, delete_buttons

# 绘制添加计划区域


def draw_add_plan(y_pos):
    add_plan_rect = pygame.Rect(540, y_pos + 20, 440, 120)
    pygame.draw.rect(screen, WHITE, add_plan_rect)
    pygame.draw.rect(screen, BLACK, add_plan_rect, 2)

    # 标题
    add_title = normal_font.render("Add New Plan", True, BLUE)
    screen.blit(add_title, (add_plan_rect.x + 10, add_plan_rect.y + 10))

    return add_plan_rect

# 绘制底部按钮


def draw_bottom_buttons():
    buttons = []

    # 上个月按钮
    prev_month_btn = Button(20, 600, 120, 40, "Prev Month")
    prev_month_btn.draw(screen)
    buttons.append(("prev_month", prev_month_btn))

    # 今天按钮
    today_btn = Button(180, 600, 120, 40, "Today")
    today_btn.draw(screen)
    buttons.append(("today", today_btn))

    # 下个月按钮
    next_month_btn = Button(340, 600, 120, 40, "Next Month")
    next_month_btn.draw(screen)
    buttons.append(("next_month", next_month_btn))

    # 清空今天计划按钮
    clear_btn = Button(540, 600, 120, 40, "Clear Plans", RED, (180, 0, 0))
    clear_btn.draw(screen)
    buttons.append(("clear", clear_btn))

    # 保存按钮
    save_btn = Button(700, 600, 120, 40, "Save", GREEN, (0, 130, 0))
    save_btn.draw(screen)
    buttons.append(("save", save_btn))

    # 退出按钮
    quit_btn = Button(860, 600, 120, 40, "Quit", PURPLE, (100, 0, 100))
    quit_btn.draw(screen)
    buttons.append(("quit", quit_btn))

    return buttons

# 绘制统计信息


def draw_stats():
    # 绘制统计区域背景
    stats_rect = pygame.Rect(20, 650, 500, 40)
    pygame.draw.rect(screen, WHITE, stats_rect)
    pygame.draw.rect(screen, BLACK, stats_rect, 1)

    # 统计有计划的日期数量
    plan_days = len(plans)
    total_plans = sum(len(plans[date]) for date in plans)

    stats_text = f"Days with plans: {plan_days} | Total plans: {total_plans}"
    stats_surface = small_font.render(stats_text, True, DARK_BLUE)
    screen.blit(stats_surface, (stats_rect.x + 10, stats_rect.y + 10))

# 主函数


def main():
    global current_year, current_month, selected_date, plans

    # 创建输入框
    plan_input = InputBox(550, 450, 350, 40, '', 'Enter plan content...')
    time_input = InputBox(550, 500, 150, 40, '', 'Time (optional)')

    # 创建添加按钮
    add_button = Button(720, 500, 100, 40, "Add")

    # 主循环
    clock = pygame.time.Clock()
    running = True

    while running:
        screen.fill(LIGHT_GRAY)

        # 绘制日历
        clicked_date = draw_calendar()
        if clicked_date and clicked_date != selected_date:
            selected_date = clicked_date

        # 绘制计划列表
        plans_y_end, delete_buttons = draw_plans()

        # 绘制添加计划区域
        add_plan_area = draw_add_plan(plans_y_end)

        # 绘制输入框
        plan_input.draw(screen)
        time_input.draw(screen)

        # 绘制添加按钮
        add_button.draw(screen)

        # 绘制底部按钮
        bottom_buttons = draw_bottom_buttons()

        # 绘制统计信息
        draw_stats()

        # 事件处理
        for event in pygame.event.get():
            if event.type == QUIT:
                running = False

            # 输入框事件
            if plan_input.handle_event(event):
                # 按回车键时添加计划
                if plan_input.get_text():
                    date_key = selected_date.isoformat()
                    if date_key not in plans:
                        plans[date_key] = []

                    time_text = f"[{time_input.get_text()}] " if time_input.get_text(
                    ) else ""
                    plans[date_key].append(time_text + plan_input.get_text())
                    save_plans()
                    plan_input.clear()
                    time_input.clear()

            if time_input.handle_event(event):
                # 时间输入框按回车时聚焦到计划输入框
                plan_input.active = True
                time_input.active = False

            # 添加按钮事件
            if add_button.is_clicked(event) and plan_input.get_text():
                date_key = selected_date.isoformat()
                if date_key not in plans:
                    plans[date_key] = []

                time_text = f"[{time_input.get_text()}] " if time_input.get_text(
                ) else ""
                plans[date_key].append(time_text + plan_input.get_text())
                save_plans()
                plan_input.clear()
                time_input.clear()

            # 删除按钮事件
            for delete_btn, plan_index in delete_buttons:
                if delete_btn.is_clicked(event):
                    date_key = selected_date.isoformat()
                    if date_key in plans and plan_index < len(plans[date_key]):
                        plans[date_key].pop(plan_index)
                        if not plans[date_key]:
                            del plans[date_key]
                        save_plans()
                    break

            # 底部按钮事件
            for btn_name, button in bottom_buttons:
                if button.is_clicked(event):
                    if btn_name == "prev_month":
                        if current_month == 1:
                            current_month = 12
                            current_year -= 1
                        else:
                            current_month -= 1

                    elif btn_name == "next_month":
                        if current_month == 12:
                            current_month = 1
                            current_year += 1
                        else:
                            current_month += 1

                    elif btn_name == "today":
                        selected_date = current_date
                        current_year = selected_date.year
                        current_month = selected_date.month

                    elif btn_name == "clear":
                        date_key = selected_date.isoformat()
                        if date_key in plans:
                            del plans[date_key]
                            save_plans()

                    elif btn_name == "save":
                        save_plans()
                        # 显示保存成功的提示
                        save_text = normal_font.render(
                            "Plans saved!", True, GREEN)
                        screen.blit(save_text, (WIDTH//2 - 60, HEIGHT - 60))
                        pygame.display.flip()
                        pygame.time.delay(1000)  # 显示1秒

                    elif btn_name == "quit":
                        running = False

            # 键盘快捷键
            if event.type == KEYDOWN:
                if event.key == K_ESCAPE:
                    running = False
                elif event.key == K_s and pygame.key.get_mods() & pygame.KMOD_CTRL:
                    save_plans()
                elif event.key == K_LEFT:
                    # 上个月
                    if current_month == 1:
                        current_month = 12
                        current_year -= 1
                    else:
                        current_month -= 1
                elif event.key == K_RIGHT:
                    # 下个月
                    if current_month == 12:
                        current_month = 1
                        current_year += 1
                    else:
                        current_month += 1
                elif event.key == K_t and pygame.key.get_mods() & pygame.KMOD_CTRL:
                    # 回到今天
                    selected_date = current_date
                    current_year = selected_date.year
                    current_month = selected_date.month

        # 显示操作提示
        help_text = small_font.render(
            "Click date to select | Ctrl+S: Save | Ctrl+T: Today | Arrow keys: Change month | Esc: Quit", True, DARK_BLUE)
        screen.blit(
            help_text, (WIDTH//2 - help_text.get_width()//2, HEIGHT - 30))

        # 显示当前日期
        current_date_text = small_font.render(
            f"Current: {current_date.month}/{current_date.day}/{current_date.year}", True, BLUE)
        screen.blit(current_date_text, (WIDTH - 200, 20))

        pygame.display.flip()
        clock.tick(60)

    pygame.quit()
    sys.exit()


if __name__ == "__main__":
    main()
