import pygame
import sys

# Initialize Pygame
pygame.init()

# Constants
WINDOW_WIDTH = 550
WINDOW_HEIGHT = 650
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GRAY = (200, 200, 200)
DARK_GRAY = (100, 100, 100)
BLUE = (70, 130, 220)
DARK_BLUE = (50, 90, 170)
LIGHT_BLUE = (230, 240, 255)
GREEN = (76, 175, 80)
RED = (244, 67, 54)
ORANGE = (255, 152, 0)
BG_COLOR = (245, 247, 250)

# Unit data
UNITS = [
    ('Millimeter', 'mm', 0.001),
    ('Centimeter', 'cm', 0.01),
    ('Meter', 'm', 1.0),
    ('Kilometer', 'km', 1000.0),
    ('Inch', 'in', 0.0254),
    ('Foot', 'ft', 0.3048),
    ('Yard', 'yd', 0.9144),
    ('Mile', 'mi', 1609.344),
    ('Nautical Mile', 'nmi', 1852.0)
]

class Button:
    def __init__(self, x, y, width, height, text, color, hover_color, text_color=WHITE):
        self.rect = pygame.Rect(x, y, width, height)
        self.text = text
        self.color = color
        self.hover_color = hover_color
        self.text_color = text_color
        self.is_hovered = False

    def draw(self, screen, font):
        color = self.hover_color if self.is_hovered else self.color
        pygame.draw.rect(screen, color, self.rect, border_radius=8)
        pygame.draw.rect(screen, DARK_GRAY, self.rect, 2, border_radius=8)
        
        text_surf = font.render(self.text, True, self.text_color)
        text_rect = text_surf.get_rect(center=self.rect.center)
        screen.blit(text_surf, text_rect)

    def handle_event(self, event):
        if event.type == pygame.MOUSEMOTION:
            self.is_hovered = self.rect.collidepoint(event.pos)
        elif event.type == pygame.MOUSEBUTTONDOWN:
            if self.is_hovered:
                return True
        return False

class Dropdown:
    def __init__(self, x, y, width, height, options, default_index=0):
        self.rect = pygame.Rect(x, y, width, height)
        self.options = options
        self.selected_index = default_index
        self.is_open = False
        self.option_height = 32
        self.scroll_offset = 0
        self.max_visible = 6

    def draw(self, screen, font):
        # Main box
        color = LIGHT_BLUE if self.is_open else WHITE
        pygame.draw.rect(screen, color, self.rect, border_radius=6)
        pygame.draw.rect(screen, BLUE, self.rect, 2, border_radius=6)
        
        # Selected text
        text = self.options[self.selected_index][:22] + '...' if len(self.options[self.selected_index]) > 25 else self.options[self.selected_index]
        text_surf = font.render(text, True, BLACK)
        screen.blit(text_surf, (self.rect.x + 10, self.rect.y + 8))
        
        # Arrow
        arrow_points = []
        if self.is_open:
            arrow_points = [(self.rect.right - 20, self.rect.centery - 4),
                           (self.rect.right - 10, self.rect.centery + 4),
                           (self.rect.right - 15, self.rect.centery)]
        else:
            arrow_points = [(self.rect.right - 20, self.rect.centery + 4),
                           (self.rect.right - 10, self.rect.centery - 4),
                           (self.rect.right - 15, self.rect.centery)]
        if arrow_points:
            pygame.draw.polygon(screen, DARK_GRAY, arrow_points)

        # Dropdown list
        if self.is_open:
            list_height = min(len(self.options), self.max_visible) * self.option_height
            list_rect = pygame.Rect(self.rect.x, self.rect.bottom, self.rect.width, list_height)
            
            # Background
            pygame.draw.rect(screen, WHITE, list_rect, border_radius=6)
            pygame.draw.rect(screen, BLUE, list_rect, 2, border_radius=6)
            
            # Items
            visible_options = self.options[:self.max_visible]
            for i, opt in enumerate(visible_options):
                item_rect = pygame.Rect(list_rect.x + 2, list_rect.y + i * self.option_height + 2,
                                       list_rect.width - 4, self.option_height - 4)
                
                # Highlight on hover
                mouse_pos = pygame.mouse.get_pos()
                if item_rect.collidepoint(mouse_pos):
                    pygame.draw.rect(screen, LIGHT_BLUE, item_rect, border_radius=4)
                
                text_surf = font.render(opt[:22], True, BLACK)
                screen.blit(text_surf, (item_rect.x + 8, item_rect.y + 6))

    def handle_event(self, event):
        if event.type == pygame.MOUSEBUTTONDOWN:
            # Toggle dropdown
            if self.rect.collidepoint(event.pos):
                self.is_open = not self.is_open
                return None
            
            # Check dropdown items
            if self.is_open:
                list_rect = pygame.Rect(self.rect.x, self.rect.bottom, self.rect.width,
                                       min(len(self.options), self.max_visible) * self.option_height)
                if list_rect.collidepoint(event.pos):
                    idx = (event.pos[1] - list_rect.y) // self.option_height
                    if 0 <= idx < len(self.options):
                        self.selected_index = idx
                        self.is_open = False
                        return idx
                else:
                    self.is_open = False
        return None

class App:
    def __init__(self):
        self.screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
        pygame.display.set_caption("Length Unit Converter")
        self.clock = pygame.time.Clock()
        self.font_large = pygame.font.Font(None, 48)
        self.font_medium = pygame.font.Font(None, 34)
        self.font_small = pygame.font.Font(None, 26)
        self.font_tiny = pygame.font.Font(None, 20)
        
        # State
        self.input_value = ""
        self.active_input = False
        self.result = None
        self.result_detail = ""
        self.error_message = ""
        
        # UI Elements
        self.setup_ui()
        
    def setup_ui(self):
        # Input box
        self.input_rect = pygame.Rect(75, 120, 380, 55)
        
        # Dropdowns
        unit_names = [f"{u[0]} ({u[1]})" for u in UNITS]
        self.from_dropdown = Dropdown(75, 210, 190, 42, unit_names, default_index=2)
        self.to_dropdown = Dropdown(285, 210, 190, 42, unit_names, default_index=3)
        
        # Buttons
        btn_y = 295
        self.convert_btn = Button(75, btn_y, 140, 44, "Convert", GREEN, (56, 142, 60))
        self.swap_btn = Button(235, btn_y, 65, 52, "⇄", ORANGE, (227, 128, 38))
        self.clear_btn = Button(320, btn_y, 155, 44, "Clear", RED, (198, 40, 33))
        
    def run(self):
        running = True
        while running:
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    running = False
                
                # Handle input
                if event.type == pygame.MOUSEBUTTONDOWN:
                    self.active_input = self.input_rect.collidepoint(event.pos)
                
                if event.type == pygame.KEYDOWN and self.active_input:
                    if event.key == pygame.K_RETURN:
                        self.perform_conversion()
                    elif event.key == pygame.K_BACKSPACE:
                        self.input_value = self.input_value[:-1]
                    elif event.key == pygame.K_MINUS and self.input_value == "":
                        self.input_value = "-"
                    elif event.key == pygame.K_PERIOD and '.' not in self.input_value:
                        self.input_value += '.'
                    elif event.unicode.isdigit() or (event.unicode == '-' and self.input_value == ""):
                        self.input_value += event.unicode
                
                # Handle dropdowns
                result = self.from_dropdown.handle_event(event)
                if result is not None:
                    pass  # Selection changed
                
                result = self.to_dropdown.handle_event(event)
                if result is not None:
                    pass  # Selection changed
                
                # Handle buttons
                if self.convert_btn.handle_event(event):
                    self.perform_conversion()
                if self.swap_btn.handle_event(event):
                    self.swap_units()
                if self.clear_btn.handle_event(event):
                    self.clear_all()
            
            self.draw()
            pygame.display.flip()
            self.clock.tick(60)
        
        pygame.quit()
        sys.exit()

    def perform_conversion(self):
        if not self.input_value:
            self.error_message = "Please enter a value"
            self.result = None
            return
        
        try:
            value = float(self.input_value)
            from_idx = self.from_dropdown.selected_index
            to_idx = self.to_dropdown.selected_index
            
            from_factor = UNITS[from_idx][2]
            to_factor = UNITS[to_idx][2]
            
            value_in_meters = value * from_factor
            result = value_in_meters / to_factor
            
            # Format result
            if abs(result) < 0.0001 or abs(result) >= 10000000:
                result_str = f"{result:.6e}"
            elif result == int(result):
                result_str = str(int(result))
            else:
                result_str = f"{result:.6f}".rstrip('0').rstrip('.')
            
            from_abbr = UNITS[from_idx][1]
            to_abbr = UNITS[to_idx][1]
            
            self.result = f"{value} {from_abbr} = {result_str} {to_abbr}"
            self.result_detail = f"{value} × {from_factor} ÷ {to_factor} = {result_str}"
            self.error_message = ""
            
        except ValueError:
            self.error_message = "Invalid number"
            self.result = None

    def swap_units(self):
        temp = self.from_dropdown.selected_index
        self.from_dropdown.selected_index = self.to_dropdown.selected_index
        self.to_dropdown.selected_index = temp
        
        if self.input_value:
            self.perform_conversion()

    def clear_all(self):
        self.input_value = ""
        self.result = None
        self.result_detail = ""
        self.error_message = ""
        self.active_input = False

    def draw(self):
        self.screen.fill(BG_COLOR)
        
        # Title
        title_surf = self.font_large.render("Length Converter", True, BLACK)
        title_rect = title_surf.get_rect(center=(WINDOW_WIDTH//2, 45))
        self.screen.blit(title_surf, title_rect)
        
        # Decorative line
        pygame.draw.line(self.screen, BLUE, (150, 72), (WINDOW_WIDTH-150, 73), 3)
        
        # Input label
        label_surf = self.font_small.render("Value:", True, DARK_GRAY)
        self.screen.blit(label_surf, (75, 98))
        
        # Input box
        input_color = BLUE if self.active_input else GRAY
        pygame.draw.rect(self.screen, WHITE, self.input_rect, border_radius=8)
        pygame.draw.rect(self.screen, input_color, self.input_rect, 2, border_radius=8)
        
        # Input text
        display_text = self.input_value if self.input_value else "0"
        text_surf = self.font_medium.render(display_text, True, BLACK)
        text_rect = text_surf.get_rect(midleft=(self.input_rect.x + 15, self.input_rect.centery))
        self.screen.blit(text_surf, text_rect)
        
        # Draw dropdowns
        self.from_dropdown.draw(self.screen, self.font_tiny)
        self.to_dropdown.draw(self.screen, self.font_tiny)
        
        # Draw buttons
        self.convert_btn.draw(self.screen, self.font_small)
        self.swap_btn.draw(self.screen, self.font_small)
        self.clear_btn.draw(self.screen, self.font_small)
        
        # Result area
        result_y = 370
        pygame.draw.rect(self.screen, LIGHT_BLUE, (50, result_y, WINDOW_WIDTH-100, 110), border_radius=12)
        
        if self.error_message:
            error_surf = self.font_small.render(self.error_message, True, RED)
            error_rect = error_surf.get_rect(center=(WINDOW_WIDTH//2, result_y + 40))
            self.screen.blit(error_surf, error_rect)
        elif self.result:
            result_surf = self.font_medium.render(self.result, True, BLACK)
            result_rect = result_surf.get_rect(center=(WINDOW_WIDTH//2, result_y + 35))
            self.screen.blit(result_surf, result_rect)
            
            detail_surf = self.font_tiny.render(self.result_detail, True, DARK_GRAY)
            detail_rect = detail_surf.get_rect(center=(WINDOW_WIDTH//2, result_y + 85))
            self.screen.blit(detail_surf, detail_rect)
        else:
            hint_surf = self.font_small.render("Enter a value and click Convert", True, DARK_GRAY)
            hint_rect = hint_surf.get_rect(center=(WINDOW_WIDTH//2, result_y + 43))
            self.screen.blit(hint_surf, hint_rect)
        
        # Quick reference
        ref_y = 510
        pygame.draw.rect(self.screen, WHITE, (50, ref_y, WINDOW_WIDTH-100, 115), border_radius=10)
        pygame.draw.rect(self.screen, GRAY, (50, ref_y, WINDOW_WIDTH-100, 115), 1, border_radius=10)
        
        ref_title = self.font_tiny.render("Quick Reference", True, BLACK)
        self.screen.blit(ref_title, (65, ref_y + 10))
        
        refs = [
            "1 m = 100 cm = 1000 mm",
            "1 km = 1000 m",
            "1 ft = 12 in = 0.3048 m",
            "1 mile = 1760 yd = 1609.344 m"
        ]
        for i, ref in enumerate(refs):
            ref_surf = self.font_tiny.render(ref, True, DARK_GRAY)
            self.screen.blit(ref_surf, (75, ref_y + 37 + i * 19))

if __name__ == "__main__":
    app = App()
    app.run()