import pygame
import sys
from datetime import datetime
import json
import os

# Initialize Pygame
pygame.init()

# Color definitions
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 50, 50)
GREEN = (50, 200, 100)
BLUE = (50, 150, 255)
PINK = (255, 182, 193)
GOLD = (255, 215, 0)
GRAY = (200, 200, 200)
DARK_GRAY = (80, 80, 80)

# Window settings
WIDTH, HEIGHT = 900, 650
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("🎂 Birthday Reminder")
clock = pygame.time.Clock()
font_large = pygame.font.Font(None, 52)
font_mid = pygame.font.Font(None, 36)
font_small = pygame.font.Font(None, 26)

# Data file path
DATA_FILE = "birthdays.json"

class BirthdayManager:
    def __init__(self):
        self.birthdays = []
        self.load_data()
        
    def load_data(self):
        """Load birthday data from file"""
        if os.path.exists(DATA_FILE):
            try:
                with open(DATA_FILE, 'r', encoding='utf-8') as f:
                    data = json.load(f)
                    for item in data:
                        item['date'] = datetime.strptime(item['date'], '%m-%d')
                    self.birthdays = data
            except:
                self.birthdays = []
        else:
            # Add sample data
            today = datetime.now()
            sample_dates = [
                {'name': 'Alice', 'date': datetime(today.year, 1, 15), 'relation': 'Friend'},
                {'name': 'Bob', 'date': datetime(today.year, 7, 31), 'relation': 'Family'},
                {'name': 'Charlie', 'date': datetime(today.year, 12, 25), 'relation': 'Colleague'},
            ]
            self.birthdays = sample_dates
            self.save_data()
    
    def save_data(self):
        """Save birthday data to file"""
        data_to_save = []
        for item in self.birthdays:
            data_to_save.append({
                'name': item['name'],
                'date': item['date'].strftime('%m-%d'),
                'relation': item['relation']
            })
        with open(DATA_FILE, 'w', encoding='utf-8') as f:
            json.dump(data_to_save, f, ensure_ascii=False, indent=2)
    
    def add_birthday(self, name, date_str, relation=''):
        """Add a new birthday record"""
        try:
            date = datetime.strptime(date_str, '%Y-%m-%d')
            self.birthdays.append({
                'name': name,
                'date': date,
                'relation': relation
            })
            self.save_data()
            return True
        except:
            return False
    
    def delete_birthday(self, index):
        """Delete a birthday record"""
        if 0 <= index < len(self.birthdays):
            del self.birthdays[index]
            self.save_data()
            return True
        return False
    
    def get_upcoming_birthdays(self, days=90):
        """Get birthdays within the next X days"""
        today = datetime.now()
        upcoming = []
        
        for b in self.birthdays:
            this_year_birthday = b['date'].replace(year=today.year)
            
            if this_year_birthday < today:
                next_birthday = b['date'].replace(year=today.year + 1)
            else:
                next_birthday = this_year_birthday
            
            delta = (next_birthday - today).days
            if 0 <= delta <= days:
                upcoming.append((b, delta, next_birthday))
        
        upcoming.sort(key=lambda x: x[1])
        return upcoming
    
    def check_today_birthday(self):
        """Check if anyone has birthday today"""
        today = datetime.now()
        today_birthdays = []
        
        for b in self.birthdays:
            if b['date'].month == today.month and b['date'].day == today.day:
                today_birthdays.append(b)
        
        return today_birthdays

def draw_text(text, font, color, x, y, center=True):
    """Draw text on screen"""
    text_surface = font.render(text, True, color)
    text_rect = text_surface.get_rect()
    if center:
        text_rect.center = (x, y)
    else:
        text_rect.topleft = (x, y)
    screen.blit(text_surface, text_rect)
    return text_rect

def draw_button(text, rect, color, hover_color):
    """Draw an interactive button"""
    mouse_pos = pygame.mouse.get_pos()
    is_hover = rect.collidepoint(mouse_pos)
    
    pygame.draw.rect(screen, hover_color if is_hover else color, rect, border_radius=12)
    pygame.draw.rect(screen, BLACK, rect, 2, border_radius=12)
    
    text_surf = font_small.render(text, True, BLACK)
    text_rect = text_surf.get_rect(center=rect.center)
    screen.blit(text_surf, text_rect)
    
    return is_hover

def draw_list_item(text, rect, color, bg_color=None):
    """Draw a clickable list item"""
    mouse_pos = pygame.mouse.get_pos()
    is_hover = rect.collidepoint(mouse_pos)
    
    if bg_color:
        pygame.draw.rect(screen, bg_color, rect, border_radius=5)
    if is_hover:
        pygame.draw.rect(screen, (220, 240, 255), rect, border_radius=5)
    
    text_surf = font_small.render(text, True, color)
    text_rect = text_surf.get_rect(midleft=(rect.x + 10, rect.centery))
    screen.blit(text_surf, text_rect)
    
    return is_hover

def main():
    manager = BirthdayManager()
    running = True
    input_mode = False
    input_name = ''
    input_date = ''
    input_relation = ''
    current_input = 'name'  # name, date, relation
    message = ''
    message_time = 0
    show_all = False
    selected_index = -1
    scroll_offset = 0
    
    while running:
        screen.fill(WHITE)
        mouse_pos = pygame.mouse.get_pos()
        
        # Title
        draw_text("🎂 Birthday Reminder", font_large, PINK, WIDTH//2, 38)
        draw_text("Never forget an important date!", font_small, GRAY, WIDTH//2, 72)
        
        # Today's birthday alert
        today_birthdays = manager.check_today_birthday()
        if today_birthdays:
            y_offset = 105
            for b in today_birthdays:
                draw_text(f"🎉 TODAY is {b['name']}'s Birthday! ({b['relation']})", 
                         font_mid, RED, WIDTH//2, y_offset)
                y_offset += 42
        
        # Upcoming birthdays section
        upcoming = manager.get_upcoming_birthdays(90)
        section_y = 155 if today_birthdays else 115
        
        # Section header
        draw_text("📅 Upcoming Birthdays:", font_mid, BLUE, WIDTH//2, section_y)
        
        # Display upcoming birthdays
        y_offset = section_y + 37
        limit = len(upcoming) if show_all else min(6, len(upcoming))
        
        if upcoming:
            for i in range(limit):
                b, days, next_date = upcoming[i]
                color = RED if days == 0 else (GREEN if days <= 7 else BLACK)
                
                if days == 0:
                    day_str = "TODAY! 🎉"
                elif days == 1:
                    day_str = "Tomorrow!"
                else:
                    day_str = f"In {days} days"
                
                date_str = next_date.strftime('%b %d')
                text = f"  {b['name']:12} ({b['relation']:8}) - {date_str:8} → {day_str}"
                draw_text(text, font_small, color, WIDTH//2, y_offset)
                y_offset += 27
            
            if len(upcoming) > 6:
                more_text = f"... and {len(upcoming)-6} more" if not show_all else ""
                draw_text(more_text, font_small, GRAY, WIDTH//2, y_offset)
                y_offset += 33
                
                toggle_btn = pygame.Rect(WIDTH//2-70, y_offset, 140, 34)
                draw_button("Show All" if not show_all else "Collapse", 
                           toggle_btn, GRAY, DARK_GRAY)
                y_offset += 44
        else:
            draw_text("No upcoming birthdays found", font_small, GRAY, WIDTH//2, y_offset)
            y_offset += 56
        
        # Separator line
        sep_y = max(y_offset + 5, 370)
        pygame.draw.line(screen, GRAY, (50, sep_y), (WIDTH-50, sep_y), 2)
        
        # All birthdays list
        list_y = sep_y + 18
        draw_text("📋 All Birthdays:", font_mid, BLUE, WIDTH//2, list_y)
        
        # List area
        list_start_y = list_y + 35
        list_height = HEIGHT - list_start_y - 85
        visible_count = min(len(manager.birthdays), list_height // 23)
        
        for i in range(visible_count):
            idx = i + scroll_offset
            if idx >= len(manager.birthdays):
                break
                
            b = manager.birthdays[idx]
            date_str = b['date'].strftime('%b %d')
            text = f"  {idx+1:2}. {b['name']:12} - {date_str:8} ({b['relation']})"
            
            item_rect = pygame.Rect(60, list_start_y + i*25, WIDTH-340, 24)
            is_selected = (idx == selected_index)
            bg = (230, 245, 255) if is_selected else None
            draw_list_item(text, item_rect, BLACK, bg)
            
            if is_selected:
                delete_btn = pygame.Rect(WIDTH-260, list_start_y + i*25, 100, 24)
                draw_button("🗑️ Delete", delete_btn, RED, (230, 80, 80))
        
        # Scroll indicators
        if scroll_offset > 0:
            draw_text("▲", font_small, GRAY, WIDTH-120, list_start_y)
        if scroll_offset + visible_count < len(manager.birthdays):
            draw_text("▼", font_small, GRAY, WIDTH-120, list_start_y + list_height - 20)
        
        # Bottom buttons
        btn_y = HEIGHT - 58
        btn_add = pygame.Rect(30, btn_y, 140, 42)
        btn_edit = pygame.Rect(190, btn_y, 140, 42)
        btn_refresh = pygame.Rect(350, btn_y, 125, 42)
        btn_exit = pygame.Rect(495, btn_y, 145, 42)
        btn_stats = pygame.Rect(660, btn_y, 205, 42)
        
        draw_button("➕ Add Birthday", btn_add, GREEN, (100, 225, 100))
        draw_button("✏️ Edit Selected", btn_edit, BLUE, (80, 175, 235))
        draw_button("🔄 Refresh", btn_refresh, GRAY, DARK_GRAY)
        draw_button("❌ Exit", btn_exit, RED, (230, 80, 80))
        
        # Stats
        total = len(manager.birthdays)
        upcoming_count = len(upcoming)
        stats_text = f"Total: {total}  |  Upcoming: {upcoming_count}"
        draw_text(stats_text, font_small, DARK_GRAY, WIDTH//2, HEIGHT-82)
        
        # Message display
        if message and pygame.time.get_ticks() - message_time < 3000:
            msg_bg = pygame.Rect(WIDTH//2-200, HEIGHT-135, 400, 35)
            pygame.draw.rect(screen, (255, 255, 224), msg_bg, border_radius=8)
            pygame.draw.rect(screen, GOLD, msg_bg, 2, border_radius=8)
            draw_text(message, font_small, BLACK, WIDTH//2, HEIGHT-118)
        
        # Input mode overlay
        if input_mode:
            overlay = pygame.Surface((WIDTH, HEIGHT))
            overlay.set_alpha(138)
            overlay.fill(BLACK)
            screen.blit(overlay, (0, 0))
            
            # Input dialog box
            dialog_w, dialog_h = 450, 310
            dialog_x, dialog_y = WIDTH//2-dialog_w//2, HEIGHT//2-dialog_h//2
            dialog_rect = pygame.Rect(dialog_x, dialog_y, dialog_w, dialog_h)
            pygame.draw.rect(screen, WHITE, dialog_rect, border_radius=18)
            pygame.draw.rect(screen, BLUE, dialog_rect, 3, border_radius=18)
            
            draw_text("✨ Add New Birthday", font_mid, BLACK, WIDTH//2, dialog_y+30)
            
            # Input fields
            prompts = {
                'name': 'Name:',
                'date': 'Birthday (YYYY-MM-DD):',
                'relation': 'Relation (optional):'
            }
            values = {
                'name': input_name,
                'date': input_date,
                'relation': input_relation
            }
            
            field_y = dialog_y + 68
            for key in ['name', 'date', 'relation']:
                # Label
                label = font_small.render(prompts[key], True, DARK_GRAY)
                screen.blit(label, (dialog_x+25, field_y))
                
                # Input box
                input_rect = pygame.Rect(dialog_x+25, field_y+22, dialog_w-50, 32)
                is_focused = (current_input == key)
                border_color = BLUE if is_focused else GRAY
                pygame.draw.rect(screen, (248, 249, 252), input_rect, border_radius=6)
                pygame.draw.rect(screen, border_color, input_rect, 2, border_radius=6)
                
                # Text
                display_text = values[key] + ('|' if is_focused else '')
                text_surf = font_small.render(display_text, True, BLACK)
                text_rect = text_surf.get_rect(midleft=(input_rect.x+8, input_rect.centery))
                # Clip text if too long
                clip_rect = input_rect.copy()
                clip_rect.x += 5
                clip_rect.width -= 10
                screen.set_clip(clip_rect)
                screen.blit(text_surf, text_rect)
                screen.set_clip(None)
                
                field_y += 78
            
            # Buttons
            confirm_btn = pygame.Rect(dialog_x+50, dialog_y+dialog_h-62, 140, 38)
            cancel_btn = pygame.Rect(dialog_x+dialog_w-190, dialog_y+dialog_h-62, 140, 38)
            
            draw_button("✅ Confirm", confirm_btn, GREEN, (100, 225, 100))
            draw_button("❌ Cancel", cancel_btn, RED, (230, 80, 80))
        
        # Event handling
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            
            elif event.type == pygame.MOUSEWHEEL:
                if not input_mode:
                    scroll_offset = max(0, min(scroll_offset - event.y, 
                                               max(0, len(manager.birthdays) - visible_count)))
            
            elif event.type == pygame.MOUSEBUTTONDOWN:
                if input_mode:
                    # Check input field clicks
                    field_y = dialog_y + 95
                    for key in ['name', 'date', 'relation']:
                        input_rect = pygame.Rect(dialog_x+25, field_y, dialog_w-50, 32)
                        if input_rect.collidepoint(event.pos):
                            current_input = key
                            break
                        field_y += 63
                    
                    if confirm_btn.collidepoint(event.pos):
                        if input_name and input_date:
                            success = manager.add_birthday(input_name, input_date, input_relation)
                            if success:
                                message = f"✅ Successfully added {input_name}'s birthday!"
                            else:
                                message = "❌ Invalid date format. Use YYYY-MM-DD"
                            message_time = pygame.time.get_ticks()
                        else:
                            message = "⚠️ Name and birthday are required"
                            message_time = pygame.time.get_ticks()
                        
                        input_mode = False
                        input_name = ''
                        input_date = ''
                        input_relation = ''
                        current_input = 'name'
                        selected_index = -1
                    
                    elif cancel_btn.collidepoint(event.pos):
                        input_mode = False
                        input_name = ''
                        input_date = ''
                        input_relation = ''
                        current_input = 'name'
                        selected_index = -1
                
                else:
                    # Check list item clicks
                    for i in range(visible_count):
                        idx = i + scroll_offset
                        if idx >= len(manager.birthdays):
                            break
                        
                        item_rect = pygame.Rect(60, list_start_y + i*25, WIDTH-380, 24)
                        if item_rect.collidepoint(event.pos):
                            if selected_index == idx:
                                selected_index = -1
                            else:
                                selected_index = idx
                            break
                        
                        # Check delete button on selected item
                        if selected_index == idx:
                            delete_btn = pygame.Rect(WIDTH-280, list_start_y + i*25, 110, 24)
                            if delete_btn.collidepoint(event.pos):
                                deleted_name = manager.birthdays[idx]['name']
                                manager.delete_birthday(idx)
                                message = f"🗑️ Deleted {deleted_name}'s birthday"
                                message_time = pygame.time.get_ticks()
                                selected_index = -1
                                break
                    
                    # Check bottom buttons
                    if btn_add.collidepoint(event.pos):
                        input_mode = True
                        current_input = 'name'
                    elif btn_edit.collidepoint(event.pos):
                        if selected_index >= 0 and selected_index < len(manager.birthdays):
                            b = manager.birthdays[selected_index]
                            input_mode = True
                            input_name = b['name']
                            input_date = b['date'].strftime('%Y-%m-%d')
                            input_relation = b['relation']
                            current_input = 'name'
                            # Remove old entry, will be re-added on confirm
                            manager.delete_birthday(selected_index)
                            selected_index = -1
                        else:
                            message = "⚠️ Please select a birthday first"
                            message_time = pygame.time.get_ticks()
                    elif btn_refresh.collidepoint(event.pos):
                        message = "🔄 Data refreshed"
                        message_time = pygame.time.get_ticks()
                    elif btn_exit.collidepoint(event.pos):
                        running = False
                    elif 'toggle_btn' in locals() and toggle_btn.collidepoint(event.pos):
                        show_all = not show_all
            
            elif event.type == pygame.KEYDOWN:
                if input_mode:
                    if event.key == pygame.K_TAB:
                        keys = ['name', 'date', 'relation']
                        idx = keys.index(current_input)
                        current_input = keys[(idx + 1) % 3]
                    elif event.key == pygame.K_RETURN:
                        if current_input == 'relation':
                            if input_name and input_date:
                                success = manager.add_birthday(input_name, input_date, input_relation)
                                message = f"✅ Added {input_name}'s birthday!" if success else "❌ Invalid date"
                                message_time = pygame.time.get_ticks()
                            input_mode = False
                            input_name = ''
                            input_date = ''
                            input_relation = ''
                            current_input = 'name'
                            selected_index = -1
                        else:
                            keys = ['name', 'date', 'relation']
                            idx = keys.index(current_input)
                            current_input = keys[(idx + 1) % 3]
                    elif event.key == pygame.K_ESCAPE:
                        input_mode = False
                        input_name = ''
                        input_date = ''
                        input_relation = ''
                        current_input = 'name'
                        selected_index = -1
                    else:
                        if current_input == 'name':
                            if event.key == pygame.K_BACKSPACE:
                                input_name = input_name[:-1]
                            else:
                                input_name += event.unicode
                        elif current_input == 'date':
                            if event.key == pygame.K_BACKSPACE:
                                input_date = input_date[:-1]
                            elif event.unicode.isdigit() or event.unicode in '-':
                                input_date += event.unicode
                        elif current_input == 'relation':
                            if event.key == pygame.K_BACKSPACE:
                                input_relation = input_relation[:-1]
                            else:
                                input_relation += event.unicode
                else:
                    # Keyboard shortcuts
                    if event.key == pygame.K_n:  # New birthday
                        input_mode = True
                        current_input = 'name'
                    elif event.key == pygame.K_DELETE and selected_index >= 0:
                        deleted_name = manager.birthdays[selected_index]['name']
                        manager.delete_birthday(selected_index)
                        message = f"🗑️ Deleted {deleted_name}"
                        message_time = pygame.time.get_ticks()
                        selected_index = -1
                    elif event.key == pygame.K_r:  # Refresh
                        message = "🔄 Refreshed"
                        message_time = pygame.time.get_ticks()
                    elif event.key == pygame.K_UP:
                        if selected_index > 0:
                            selected_index -= 1
                            if selected_index < scroll_offset:
                                scroll_offset = max(0, selected_index)
                    elif event.key == pygame.K_DOWN:
                        if selected_index < len(manager.birthdays) - 1:
                            selected_index += 1
                            if selected_index >= scroll_offset + visible_count:
                                scroll_offset = min(len(manager.birthdays) - visible_count, 
                                                   selected_index - visible_count + 1)
                    elif event.key == pygame.K_ESCAPE:
                        selected_index = -1
        
        pygame.display.flip()
        clock.tick(60)
    
    pygame.quit()
    sys.exit()

if __name__ == "__main__":
    main()