import pygame
import sys
import os
import win32gui
import win32con
import win32api
import win32ui
from ctypes import windll, create_unicode_buffer, sizeof, byref, c_int
import importlib.resources

TITLEBAR_HEIGHT = 40
BUTTON_WIDTH = 55
BUTTON_HEIGHT = TITLEBAR_HEIGHT
PADDING = 8

FONT = pygame.font.SysFont("Consolas", 18)
HEADER_FONT = pygame.font.SysFont("Consolas", 28, bold=True)

BG_COLOR = (30, 30, 30)
TITLE_CLIENT_BG = (25, 25, 25)
TITLE_CLIENT_TEXT = (230, 230, 230)
HEADER_SHADOW_COLOR = (20, 20, 20)
BUTTON_HOVER_BG = (150, 150, 150)
BUTTON_TEXT_COLOR = (255, 255, 255)

# Helper to get resource path for package data

def resource_path(filename):
    try:
        # Use importlib.resources for package data
        with importlib.resources.path("custom_titlebar.assets", filename) as p:
            return str(p)
    except Exception:
        # Fallback for dev mode
        return os.path.join(os.path.dirname(__file__), "assets", filename)

class CustomTitleBarWindow:
    def __init__(self, width=1200, height=700, title="", enable_scroll=False):
        pygame.init()
        self.width = width
        self.height = height
        self.title = title
        self.enable_scroll = enable_scroll
        self.screen = pygame.display.set_mode((self.width, self.height), pygame.NOFRAME)
        pygame.display.set_caption(self.title)
        self.hwnd = win32gui.GetForegroundWindow()
        self._init_window_styles()
        self._center_window()
        self.dragging = False
        self.drag_offset = (0, 0)
        self.resizing = False
        self.resize_edge = None
        self.is_maximized = False
        self.original_size = (self.width, self.height)
        self.original_pos = (0, 0)
        self.RESIZE_BORDER = 5
        self.resize_start_size = None
        self.resize_start_pos = None
        self.resize_mouse_start = None
        self.scroll_y = 0.0
        self.scroll_speed = 0.0
        self.running = True

    def _init_window_styles(self):
        style = win32gui.GetWindowLong(self.hwnd, win32con.GWL_STYLE)
        style = style & ~win32con.WS_CAPTION & ~win32con.WS_THICKFRAME
        style = style | win32con.WS_MAXIMIZEBOX | win32con.WS_MINIMIZEBOX | win32con.WS_SYSMENU
        win32gui.SetWindowLong(self.hwnd, win32con.GWL_STYLE, style)
        ex_style = win32gui.GetWindowLong(self.hwnd, win32con.GWL_EXSTYLE)
        ex_style = ex_style | win32con.WS_EX_LAYERED
        win32gui.SetWindowLong(self.hwnd, win32con.GWL_EXSTYLE, ex_style)
        try:
            import ctypes
            from ctypes import wintypes
            DWMWA_WINDOW_CORNER_PREFERENCE = 33
            DWMWCP_ROUND = 2
            ctypes.windll.dwmapi.DwmSetWindowAttribute(
                wintypes.HWND(self.hwnd),
                DWMWA_WINDOW_CORNER_PREFERENCE,
                ctypes.byref(wintypes.INT(DWMWCP_ROUND)),
                ctypes.sizeof(wintypes.INT)
            )
        except:
            pass

    def _center_window(self):
        screen_width = win32api.GetSystemMetrics(win32con.SM_CXSCREEN)
        screen_height = win32api.GetSystemMetrics(win32con.SM_CYSCREEN)
        x = (screen_width - self.width) // 2
        y = (screen_height - self.height) // 2
        win32gui.SetWindowPos(self.hwnd, 0, x, y, self.width, self.height, 0)

    def set_title(self, title):
        self.title = title
        pygame.display.set_caption(self.title)

    def handle_event(self, event):
        if event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1:
                mouse_pos = pygame.mouse.get_pos()
                if self.is_resize_area(mouse_pos):
                    self.resizing = True
                    self.resize_edge = self.get_resize_edge(mouse_pos)
                    rect = win32gui.GetWindowRect(self.hwnd)
                    self.resize_start_size = (rect[2] - rect[0], rect[3] - rect[1])
                    self.resize_start_pos = (rect[0], rect[1])
                    self.resize_mouse_start = mouse_pos
                    return True
                if mouse_pos[1] < TITLEBAR_HEIGHT:
                    min_rect, max_rect, close_rect = self.get_button_rects(self.screen.get_size()[0])
                    if not (min_rect.collidepoint(mouse_pos) or max_rect.collidepoint(mouse_pos) or close_rect.collidepoint(mouse_pos)):
                        self.dragging = True
                        self.drag_offset = (mouse_pos[0], mouse_pos[1])
                        return True
        elif event.type == pygame.MOUSEBUTTONUP:
            if event.button == 1:
                self.dragging = False
                self.resizing = False
                self.resize_edge = None
                self.resize_start_size = None
                self.resize_start_pos = None
                self.resize_mouse_start = None
        elif event.type == pygame.MOUSEMOTION:
            if self.dragging:
                self.handle_drag(event.pos)
            elif self.resizing:
                self.handle_resize(event.pos)
            else:
                self.update_cursor(event.pos)
        return False

    def update_cursor(self, pos):
        if self.is_resize_area(pos):
            edge = self.get_resize_edge(pos)
            if edge in ['left', 'right']:
                pygame.mouse.set_cursor(pygame.SYSTEM_CURSOR_SIZEWE)
            elif edge in ['top', 'bottom']:
                pygame.mouse.set_cursor(pygame.SYSTEM_CURSOR_SIZENS)
            elif edge in ['topleft', 'bottomright']:
                pygame.mouse.set_cursor(pygame.SYSTEM_CURSOR_SIZENWSE)
            elif edge in ['topright', 'bottomleft']:
                pygame.mouse.set_cursor(pygame.SYSTEM_CURSOR_SIZENESW)
        else:
            pygame.mouse.set_cursor(pygame.SYSTEM_CURSOR_ARROW)

    def is_resize_area(self, pos):
        x, y = pos
        w, h = self.screen.get_size()
        return (x < self.RESIZE_BORDER or x > w - self.RESIZE_BORDER or y < self.RESIZE_BORDER or y > h - self.RESIZE_BORDER)

    def get_resize_edge(self, pos):
        x, y = pos
        w, h = self.screen.get_size()
        if x < self.RESIZE_BORDER:
            if y < self.RESIZE_BORDER:
                return 'topleft'
            elif y > h - self.RESIZE_BORDER:
                return 'bottomleft'
            return 'left'
        elif x > w - self.RESIZE_BORDER:
            if y < self.RESIZE_BORDER:
                return 'topright'
            elif y > h - self.RESIZE_BORDER:
                return 'bottomright'
            return 'right'
        elif y < self.RESIZE_BORDER:
            return 'top'
        elif y > h - self.RESIZE_BORDER:
            return 'bottom'
        return None

    def handle_drag(self, pos):
        if not self.is_maximized:
            rect = win32gui.GetWindowRect(self.hwnd)
            x = rect[0] + (pos[0] - self.drag_offset[0])
            y = rect[1] + (pos[1] - self.drag_offset[1])
            win32gui.SetWindowPos(self.hwnd, 0, x, y, 0, 0, win32con.SWP_NOSIZE)

    def handle_resize(self, pos):
        if not self.is_maximized and self.resize_start_size and self.resize_start_pos and self.resize_mouse_start:
            start_x, start_y = self.resize_start_pos
            start_w, start_h = self.resize_start_size
            mouse_start_x, mouse_start_y = self.resize_mouse_start
            dx = pos[0] - mouse_start_x
            dy = pos[1] - mouse_start_y
            x, y = start_x, start_y
            w, h = start_w, start_h
            if self.resize_edge in ['left', 'topleft', 'bottomleft']:
                new_width = start_w - dx
                if new_width >= 400:
                    x = start_x + dx
                    w = new_width
            if self.resize_edge in ['right', 'topright', 'bottomright']:
                new_width = start_w + dx
                if new_width >= 400:
                    w = new_width
            if self.resize_edge in ['top', 'topleft', 'topright']:
                new_height = start_h - dy
                if new_height >= 300:
                    y = start_y + dy
                    h = new_height
            if self.resize_edge in ['bottom', 'bottomleft', 'bottomright']:
                new_height = start_h + dy
                if new_height >= 300:
                    h = new_height
            win32gui.SetWindowPos(self.hwnd, 0, x, y, w, h, 0)
            pygame.display.set_mode((w, h), pygame.NOFRAME)

    def maximize_window(self):
        if not self.is_maximized:
            rect = win32gui.GetWindowRect(self.hwnd)
            self.original_size = (rect[2] - rect[0], rect[3] - rect[1])
            self.original_pos = (rect[0], rect[1])
            x, y = 0, 0
            w = win32api.GetSystemMetrics(win32con.SM_CXSCREEN)
            h = win32api.GetSystemMetrics(win32con.SM_CYSCREEN)
            win32gui.SetWindowPos(self.hwnd, win32con.HWND_TOP, x, y, w, h, win32con.SWP_SHOWWINDOW)
            pygame.display.set_mode((w, h), pygame.NOFRAME)
        else:
            win32gui.SetWindowPos(self.hwnd, win32con.HWND_TOP, self.original_pos[0], self.original_pos[1], self.original_size[0], self.original_size[1], win32con.SWP_SHOWWINDOW)
            pygame.display.set_mode(self.original_size, pygame.NOFRAME)
        self.is_maximized = not self.is_maximized

    def minimize_window(self):
        win32gui.ShowWindow(self.hwnd, win32con.SW_MINIMIZE)

    def close_window(self):
        win32gui.DestroyWindow(self.hwnd)
        self.running = False

    def get_button_rects(self, window_width):
        top_y = 0
        close_x = window_width - BUTTON_WIDTH
        close_rect = pygame.Rect(close_x, top_y, BUTTON_WIDTH, BUTTON_HEIGHT)
        max_x = close_x - PADDING - BUTTON_WIDTH
        max_rect = pygame.Rect(max_x, top_y, BUTTON_WIDTH, BUTTON_HEIGHT)
        min_x = max_x - PADDING - BUTTON_WIDTH
        min_rect = pygame.Rect(min_x, top_y, BUTTON_WIDTH, BUTTON_HEIGHT)
        return min_rect, max_rect, close_rect

    def draw_titlebar(self):
        w, h = self.screen.get_size()
        self.screen.fill(BG_COLOR)
        pygame.draw.rect(self.screen, TITLE_CLIENT_BG, (0, 0, w, TITLEBAR_HEIGHT))
        title_surf = HEADER_FONT.render(self.title, True, TITLE_CLIENT_TEXT)
        title_y = TITLEBAR_HEIGHT // 2 - title_surf.get_height() // 2
        title_x = PADDING * 2
        self.screen.blit(title_surf, (title_x, title_y))
        min_rect, max_rect, close_rect = self.get_button_rects(w)
        mouse_pos = pygame.mouse.get_pos()
        mouse_pressed = pygame.mouse.get_pressed()[0]
        for rect, label in zip([min_rect, max_rect, close_rect], ["_", "□", "X"]):
            if rect.collidepoint(mouse_pos):
                bg = (200, 0, 0) if label == "X" and mouse_pressed else BUTTON_HOVER_BG
            else:
                bg = TITLE_CLIENT_BG
            pygame.draw.rect(self.screen, bg, rect)
            text_surf = FONT.render(label, True, BUTTON_TEXT_COLOR)
            text_rect = text_surf.get_rect(center=rect.center)
            self.screen.blit(text_surf, text_rect)
        return min_rect, max_rect, close_rect

    def run(self, draw_content=None):
        clock = pygame.time.Clock()
        while self.running:
            w, h = self.screen.get_size()
            min_btn, max_btn, close_btn = self.draw_titlebar()
            if draw_content:
                draw_content(self.screen, w, h, self.scroll_y)
            pygame.display.flip()
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    self.running = False
                if self.handle_event(event):
                    continue
                if event.type == pygame.MOUSEBUTTONDOWN:
                    if event.button == 1:
                        mx, my = event.pos
                        if close_btn.collidepoint(mx, my):
                            self.close_window()
                        elif max_btn.collidepoint(mx, my):
                            self.maximize_window()
                        elif min_btn.collidepoint(mx, my):
                            self.minimize_window()
                if self.enable_scroll:
                    if event.type == pygame.MOUSEBUTTONDOWN:
                        if event.button == 4:
                            self.scroll_y = max(0, self.scroll_y - 1)
                        elif event.button == 5:
                            self.scroll_y = self.scroll_y + 1
                    elif event.type == pygame.KEYDOWN:
                        if event.key == pygame.K_UP:
                            self.scroll_y = max(0, self.scroll_y - 1)
                        elif event.key == pygame.K_DOWN:
                            self.scroll_y = self.scroll_y + 1
            clock.tick(60)
        pygame.quit()
        sys.exit() 