import pygame
import json
import os
from datetime import datetime, date

# 关闭系统字体扫描，规避字体报错
os.environ['PYGAME_FORCE_SYSTEM_FONTS'] = '0'
pygame.init()

WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("日历提醒计划表（增删改）")
clock = pygame.time.Clock()
FPS = 60

# 配色
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GRAY = (200, 200, 200)
LIGHT_BLUE = (180, 220, 255)
RED = (220, 30, 30)
GREEN = (20, 180, 60)
BTN_BLUE = (70, 130, 220)
BTN_RED = (210, 60, 60)
BTN_GREEN = (40, 170, 80)

# 使用内置字体，彻底不用SysFont
font_big = pygame.font.Font(None, 32)
font_mid = pygame.font.Font(None, 24)
font_small = pygame.font.Font(None, 18)

# 日程文件
SCHEDULE_FILE = "schedule.json"

def load_schedule():
    if os.path.exists(SCHEDULE_FILE):
        with open(SCHEDULE_FILE, "r", encoding="utf-8") as f:
            return json.load(f)
    return {}

def save_schedule(data):
    with open(SCHEDULE_FILE, "w", encoding="utf-8") as f:
        json.dump(data, f, ensure_ascii=False, indent=2)

schedule = load_schedule()

# 当前日历年月
now = datetime.now()
current_year = now.year
current_month = now.month
week_names = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]

def get_month_info(y, m):
    if m == 12:
        next_month = date(y+1, 1, 1)
    else:
        next_month = date(y, m+1, 1)
    first_day = date(y, m, 1)
    total_days = (next_month - date(y, m, 1)).days
    start_week = first_day.weekday()
    return total_days, start_week

# 输入框类
class InputBox:
    def __init__(self, x, y, w, h):
        self.rect = pygame.Rect(x, y, w, h)
        self.text = ""
        self.active = False

    def handle_event(self, event):
        if event.type == pygame.MOUSEBUTTONDOWN:
            self.active = self.rect.collidepoint(event.pos)
        if event.type == pygame.KEYDOWN and self.active:
            if event.key == pygame.K_RETURN:
                return self.text
            elif event.key == pygame.K_BACKSPACE:
                self.text = self.text[:-1]
            else:
                self.text += event.unicode
        return None

    def draw(self):
        border_color = LIGHT_BLUE if self.active else GRAY
        pygame.draw.rect(screen, border_color, self.rect, 2)
        text_surface = font_small.render(self.text, True, BLACK)
        screen.blit(text_surface, (self.rect.x + 5, self.rect.y + 5))

# 弹窗全局变量
popup_type = "none"
popup_day = 0
edit_index = -1
input_box = InputBox(200, 260, 400, 40)
tip_text = ""

# 手动实现双击所需变量
last_click_time = 0
last_click_pos = (0, 0)
DOUBLE_CLICK_DELAY = 300  # 毫秒内连续点击判定双击

running = True
while running:
    screen.fill(WHITE)
    mouse_x, mouse_y = pygame.mouse.get_pos()
    click_pos = None
    current_time = pygame.time.get_ticks()

    # 事件循环
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

        # 弹窗优先处理
        if popup_type != "none":
            input_return = input_box.handle_event(event)
            if input_return is not None:
                date_key = f"{current_year}-{current_month:02d}-{popup_day:02d}"
                if date_key not in schedule:
                    schedule[date_key] = []
                if popup_type == "add":
                    schedule[date_key].append(input_return)
                elif popup_type == "edit" and 0 <= edit_index < len(schedule[date_key]):
                    schedule[date_key][edit_index] = input_return
                save_schedule(schedule)
                popup_type = "none"
                input_box.text = ""

            if event.type == pygame.MOUSEBUTTONDOWN:
                click_pos = event.pos
                popup_area = pygame.Rect(180, 200, 440, 150)
                if not popup_area.collidepoint(click_pos):
                    popup_type = "none"
                    input_box.text = ""
            continue

        # 鼠标单击事件，区分单击/双击
        if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
            click_pos = event.pos
            # 判断是否双击：位置相同 + 间隔小于300ms
            is_double = False
            if (current_time - last_click_time) < DOUBLE_CLICK_DELAY and click_pos == last_click_pos:
                is_double = True

            # 更新上次点击记录
            last_click_time = current_time
            last_click_pos = click_pos

            # 翻页按钮
            if pygame.Rect(100, 30, 80, 35).collidepoint(click_pos):
                current_month -= 1
                if current_month < 1:
                    current_month = 12
                    current_year -= 1
            elif pygame.Rect(620, 30, 80, 35).collidepoint(click_pos):
                current_month += 1
                if current_month > 12:
                    current_month = 1
                    current_year += 1

            # 遍历所有日期格子
            total_days, start_week = get_month_info(current_year, current_month)
            day_w, day_h = 90, 70
            start_x, start_y = 40, 110
            day_count = 0
            hit_cell = False

            for row in range(6):
                for col in range(7):
                    cell_x = start_x + col * day_w
                    cell_y = start_y + row * day_h
                    cell_rect = pygame.Rect(cell_x, cell_y, day_w, day_h)
                    if row == 0 and col < start_week:
                        continue
                    day_count += 1
                    if day_count > total_days:
                        break

                    if cell_rect.collidepoint(click_pos):
                        hit_cell = True
                        if is_double:
                            # 双击：打开日程列表
                            popup_type = "view"
                            popup_day = day_count
                            tip_text = f"{current_year}年{current_month}月{day_count}日 日程列表"
                        else:
                            # 单击：新建日程
                            popup_type = "add"
                            popup_day = day_count
                            tip_text = f"{current_year}年{current_month}月{day_count}日 新建日程"
                            input_box.text = ""
                        break
                if hit_cell:
                    break

    # 绘制年月标题
    title_surf = font_big.render(f"{current_year}年 {current_month}月", True, BLACK)
    screen.blit(title_surf, (WIDTH//2 - title_surf.get_width()//2, 25))
    pygame.draw.rect(screen, BTN_BLUE, (100, 30, 80, 35))
    pygame.draw.rect(screen, BTN_BLUE, (620, 30, 80, 35))
    screen.blit(font_mid.render("上月", True, WHITE), (115, 32))
    screen.blit(font_mid.render("下月", True, WHITE), (635, 32))

    # 星期表头
    week_y = 80
    for idx, week_text in enumerate(week_names):
        w_surf = font_mid.render(week_text, True, BLACK)
        x_pos = 40 + idx*90 + 45 - w_surf.get_width()//2
        screen.blit(w_surf, (x_pos, week_y))
        pygame.draw.line(screen, GRAY, (40+idx*90, week_y+30), (40+(idx+1)*90, week_y+30))

    # 绘制日期格子
    total_days, start_week = get_month_info(current_year, current_month)
    day_w, day_h = 90, 70
    start_x, start_y = 40, 110
    day_count = 0

    for row in range(6):
        for col in range(7):
            cell_x = start_x + col * day_w
            cell_y = start_y + row * day_h
            cell_rect = pygame.Rect(cell_x, cell_y, day_w, day_h)
            pygame.draw.rect(screen, GRAY, cell_rect, 1)

            if row == 0 and col < start_week:
                continue
            day_count += 1
            if day_count > total_days:
                break

            day_surf = font_mid.render(str(day_count), True, BLACK)
            screen.blit(day_surf, (cell_x+8, cell_y+5))

            date_key = f"{current_year}-{current_month:02d}-{day_count:02d}"
            if date_key in schedule and len(schedule[date_key])>0:
                pygame.draw.circle(screen, RED, (cell_x+75, cell_y+12), 6)

            if cell_rect.collidepoint(mouse_x, mouse_y):
                pygame.draw.rect(screen, LIGHT_BLUE, cell_rect, 2)

    # 弹窗绘制（新增/编辑/查看）
    if popup_type != "none":
        mask = pygame.Surface((WIDTH, HEIGHT))
        mask.set_alpha(170)
        mask.fill(BLACK)
        screen.blit(mask, (0, 0))
        pop_x, pop_y, pop_w, pop_h = 180, 200, 440, 150
        pygame.draw.rect(screen, WHITE, (pop_x, pop_y, pop_w, pop_h))
        pygame.draw.rect(screen, BLACK, (pop_x, pop_y, pop_w, pop_h), 2)
        screen.blit(font_mid.render(tip_text, True, BLACK), (pop_x+15, pop_y+8))

        date_key = f"{current_year}-{current_month:02d}-{popup_day:02d}"
        day_list = schedule.get(date_key, [])

        if popup_type in ("add", "edit"):
            input_box.draw()
            hint = font_small.render("回车保存，点击空白关闭", True, GRAY)
            screen.blit(hint, (pop_x+15, pop_y+110))

        elif popup_type == "view":
            y_offset = 40
            btn_w, btn_h = 60, 24
            for idx, content in enumerate(day_list):
                text_surf = font_small.render(f"{idx+1}. {content}", True, BLACK)
                screen.blit(text_surf, (pop_x+10, pop_y + y_offset))

                edit_btn = pygame.Rect(pop_x+240, pop_y+y_offset, btn_w, btn_h)
                pygame.draw.rect(screen, BTN_GREEN, edit_btn)
                screen.blit(font_small.render("编辑", True, WHITE), (edit_btn.x+10, edit_btn.y+2))

                del_btn = pygame.Rect(pop_x+310, pop_y+y_offset, btn_w, btn_h)
                pygame.draw.rect(screen, BTN_RED, del_btn)
                screen.blit(font_small.render("删除", True, WHITE), (del_btn.x+10, del_btn.y+2))

                if click_pos:
                    if edit_btn.collidepoint(click_pos):
                        popup_type = "edit"
                        edit_index = idx
                        input_box.text = content
                        tip_text = f"编辑第{idx+1}条日程"
                    if del_btn.collidepoint(click_pos):
                        day_list.pop(idx)
                        schedule[date_key] = day_list
                        save_schedule(schedule)
                        if len(day_list) == 0:
                            popup_type = "none"

                y_offset += 32

            if len(day_list) == 0:
                empty_text = font_small.render("当日暂无日程，单击日期添加", True, GRAY)
                screen.blit(empty_text, (pop_x+10, pop_y+50))

    pygame.display.update()
    clock.tick(FPS)

pygame.quit()