# client/inventory_window.py
import pygame
import json
from client.resource_path import get_asset_path, get_resource_path

class InventoryItem:
    """Client-side representation of an inventory item"""
    def __init__(self, item_data):
        self.id = item_data.get("id")
        self.item_id = item_data.get("item_id")
        self.item_type = item_data.get("item_type")
        self.slot_position = item_data.get("slot_position")
        self.quantity = item_data.get("quantity", 1)
        self.is_equipped = item_data.get("is_equipped", False)
        self.current_durability = item_data.get("current_durability")
        self.max_durability = item_data.get("max_durability")
        
        # Seed data (from server)
        seed_data = item_data.get("seed_data", {})
        self.name = seed_data.get("name", "Unknown Item")
        self.description = seed_data.get("description", "")
        self.grade = seed_data.get("grade", "Common")
        self.stats = seed_data.get("stats", {})
        self.requirements = seed_data.get("requirements", {})
        self.value = seed_data.get("value", 0)
        
        # Load image
        image_path = seed_data.get("image_path")
        self.image = None
        if image_path:
            try:
                self.image = pygame.image.load(image_path).convert_alpha()
            except:
                print(f"[!] Failed to load item image: {image_path}")
                # Create placeholder image
                self.image = pygame.Surface((64, 64))
                self.image.fill((100, 100, 100))


class InventoryWindow:
    def __init__(self, font, network_client, game_loop=None):
        self.original_bg = pygame.image.load(get_asset_path("images/UI/inventory.png")).convert_alpha()
        self.gear_mask = pygame.image.load(get_asset_path("images/UI/inventory_mask.png")).convert_alpha()
        self.background = self.original_bg
        self.font = font
        self.network_client = network_client
        self.game_loop = game_loop

        self.rows = 6
        self.cols = 10
        self.slots = []

        # Map colors to fields/buttons
        self.gear_color_map = {
            "Ring Left": (0, 128, 255),
            "Ring Right": (255, 128, 255),
            "Legs": (0, 128, 128),
            "Shield": (0, 0, 255),
            "Weapon": (0, 255, 0),
            "Armor": (255, 0, 0),
            "Helmet": (255, 255, 0),
            "Necklace": (255, 128, 0),
        }

        # Map gear slots to server slot names
        self.gear_to_server_slot = {
        "Weapon": "weapon_slot",
        "Helmet": "helmet_slot",
        "Armor": "chest_slot",
        "Legs": "legs_slot",
        "Gloves": "gloves_slot",
        "Necklace": "amulet_slot",
        "Ring Left": "ring1_slot",
        "Ring Right": "ring2_slot",
    }
        self.gear_slots = {} 

        # Inventory data from server
        self.items = {}  # slot_position -> InventoryItem
        self.equipped_slots = {}  # slot_name -> inventory_item_id

        # Drag & drop
        self.dragging_item = None
        self.dragging_slot = None
        self.drag_offset = (0, 0)
        
        # UI state
        self.is_open = False

    def toggle(self):
        """Toggle inventory window open/closed"""
        self.is_open = not self.is_open
        if self.is_open:
            self.request_inventory()

    def request_inventory(self):
        """Request inventory data from server"""
        message = {
            "action": "get_inventory",
            "data": {}
        }
        self.network_client.send(json.dumps(message) + "\n")

    def handle_inventory_data(self, data):
        """Handle inventory_data response from server"""
        self.items = {}
        
        # Parse items
        items_list = data.get("items", [])
        for item_data in items_list:
            item = InventoryItem(item_data)
            if item.slot_position is not None:
                self.items[item.slot_position] = item
        
        # Parse equipped items
        equipped = data.get("equipped", {})
        self.equipped_slots = {
            "weapon_slot": equipped.get("weapon_slot"),
            "helmet_slot": equipped.get("helmet_slot"),
            "chest_slot": equipped.get("chest_slot"),
            "legs_slot": equipped.get("legs_slot"),
            "boots_slot": equipped.get("boots_slot"),
            "gloves_slot": equipped.get("gloves_slot"),
            "ring1_slot": equipped.get("ring1_slot"),
            "ring2_slot": equipped.get("ring2_slot"),
            "amulet_slot": equipped.get("amulet_slot"),
        }
        
        print(f"[Inventory] Loaded {len(self.items)} items")

    def resize(self, screen):
        screen_rect = screen.get_rect()
        max_width = int(screen_rect.width * 0.8)
        max_height = int(screen_rect.height * 0.8)

        # Scale while keeping aspect ratio
        bg_rect = self.original_bg.get_rect()
        scale = min(max_width / bg_rect.width, max_height / bg_rect.height, 0.8)
        new_size = (int(bg_rect.width * scale), int(bg_rect.height * scale))
        self.background = pygame.transform.smoothscale(self.original_bg, new_size)
        self.gear_mask = pygame.transform.smoothscale(self.gear_mask, new_size)

        # Slot rects
        slot_w, slot_h = 143, 140
        start_x, start_y = 56, 81
        spacing_x = 5
        spacing_y = 10

        scale_x = new_size[0] / self.original_bg.get_width()
        scale_y = new_size[1] / self.original_bg.get_height()

        self.slots = []
        for r in range(self.rows):
            for c in range(self.cols):
                x = int((start_x + c * (slot_w + spacing_x)) * scale_x)
                y = int((start_y + r * (slot_h + spacing_y)) * scale_y)
                w = int(slot_w * scale_x)
                h = int(slot_h * scale_y)
                self.slots.append(pygame.Rect(x, y, w, h))

    def _build_gear_slots(self):
        """Build gear slot rectangles from the mask image"""
        if not hasattr(self, 'gear_mask') or not hasattr(self, 'bg_rect'):
            return
        
        self.gear_slots = {}
        width, height = self.gear_mask.get_size()
        
        # For each gear slot color, find the bounding rectangle
        for gear_name, color in self.gear_color_map.items():
            # Create a mask for this color
            mask = pygame.mask.from_threshold(
                self.gear_mask, 
                color, 
                (10, 10, 10, 255)  # Threshold for color matching
            )
            
            # Get bounding rectangles
            rects = mask.get_bounding_rects()
            if rects:
                # Take the largest rectangle (in case there are multiple)
                largest_rect = max(rects, key=lambda r: r.width * r.height)
                self.gear_slots[gear_name] = largest_rect

    def handle_event(self, event, player):
        """Handle mouse and keyboard events for inventory interaction"""
        if not self.is_open or not hasattr(self, "bg_rect"):
            return
        
        bg_rect = self.bg_rect

        if event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1:  # Left click - drag
                # Check if clicking on gear slot first
                clicked_gear = self._get_gear_slot_at_pos(event.pos, bg_rect)
                if clicked_gear:
                    self._handle_gear_slot_click(clicked_gear)
                else:
                    # Check inventory slots
                    self._handle_left_click_down(event, bg_rect)
                    
            elif event.button == 3:  # Right click - equip/use
                self._handle_right_click(event, bg_rect)

        elif event.type == pygame.MOUSEBUTTONUP and event.button == 1:
            if self.dragging_item:
                # Check if dropping on a gear slot
                dropped_gear = self._get_gear_slot_at_pos(event.pos, bg_rect)
                if dropped_gear:
                    self._handle_gear_slot_drop(dropped_gear)
                else:
                    self._handle_left_click_up(event, bg_rect)
    
    def _get_gear_slot_at_pos(self, pos, bg_rect):
        """Get the gear slot name at the given mouse position"""
        if not self.gear_slots:
            return None
        
        # Convert screen position to relative position on the gear mask
        rel_x = pos[0] - bg_rect.x
        rel_y = pos[1] - bg_rect.y
        
        for gear_name, rect in self.gear_slots.items():
            if rect.collidepoint(rel_x, rel_y):
                return gear_name
        
        return None
    
    def _handle_gear_slot_click(self, gear_name):
        """Handle clicking on a gear slot (to unequip)"""
        server_slot = self.gear_to_server_slot.get(gear_name)
        if not server_slot:
            return
        
        # Get the equipped item ID from this slot
        equipped_item_id = self.equipped_slots.get(server_slot)
        if equipped_item_id:
            # Unequip the item
            self._unequip_item(equipped_item_id)
            print(f"[Inventory] Unequipping {gear_name}")

    def _handle_gear_slot_drop(self, gear_name):
        """Handle dropping an item onto a gear slot (to equip)"""
        if self.dragging_slot is None:
            return
        
        item = self.items.get(self.dragging_slot)
        if not item:
            return
        
        # Check if the item type matches the gear slot
        item_type_to_gear = {
            "weapon": "Weapon",
            "helmet": "Helmet",
            "chest": "Armor",
            "legs": "Legs",
            "gloves": "Gloves",
            "amulet": "Necklace",
        }
    
        expected_gear = item_type_to_gear.get(item.item_type)

        # For rings, accept either ring slot
        if item.item_type in ["ring1", "ring2", "ring"]:
            if gear_name in ["Ring Left", "Ring Right"]:
                self._equip_item(item.id)
                self.dragging_item = None
                self.dragging_slot = None
                return
        
        if expected_gear == gear_name:
            self._equip_item(item.id)
            print(f"[Inventory] Equipping {item.name} to {gear_name}")
        else:
            print(f"[Inventory] Cannot equip {item.item_type} to {gear_name}")
        
        # Reset drag state
        self.dragging_item = None
        self.dragging_slot = None

    def _handle_left_click_down(self, event, bg_rect):
        """Handle left mouse button down - start dragging"""
        for i, slot in enumerate(self.slots):
            world_rect = slot.move(bg_rect.topleft)
            if world_rect.collidepoint(event.pos):
                item = self.items.get(i)
                if item:
                    # Start dragging
                    scale_factor = 0.8
                    self.dragging_item = pygame.transform.smoothscale(
                        item.image,
                        (int(world_rect.width * scale_factor), int(world_rect.height * scale_factor))
                    )
                    self.dragging_slot = i
                    self.drag_offset = (world_rect.x - event.pos[0], world_rect.y - event.pos[1])
                break

    def _handle_left_click_up(self, event, bg_rect):
        """Handle left mouse button up - drop item"""
        dropped_in_slot = False
        
        for i, slot in enumerate(self.slots):
            world_rect = slot.move(bg_rect.topleft)
            if world_rect.collidepoint(event.pos):
                # Dropped in a slot
                if i != self.dragging_slot:
                    # Move item to new slot
                    self._move_item(self.dragging_slot, i)
                dropped_in_slot = True
                break

        if not dropped_in_slot and self.dragging_slot is not None:
            # Dropped outside inventory - ask to drop/delete
            self._drop_item(self.dragging_slot)

        # Reset drag state
        self.dragging_item = None
        self.dragging_slot = None

    def _handle_right_click(self, event, bg_rect):
        """Handle right click - equip/unequip item"""
        for i, slot in enumerate(self.slots):
            world_rect = slot.move(bg_rect.topleft)
            if world_rect.collidepoint(event.pos):
                item = self.items.get(i)
                if item:
                    if item.is_equipped:
                        self._unequip_item(item.id)
                    else:
                        self._equip_item(item.id)
                break

    def _move_item(self, from_slot, to_slot):
        """Request to move item to new slot"""
        item = self.items.get(from_slot)
        if not item:
            return
        
        message = {
            "action": "move_item",
            "data": {
                "inventory_item_id": item.id,
                "new_slot_position": to_slot
            }
        }
        self.network_client.send(json.dumps(message) + "\n")
        print(f"[Inventory] Moving item {item.name} from slot {from_slot} to {to_slot}")

    def _equip_item(self, inventory_item_id):
        """Request to equip item"""
        message = {
            "action": "equip_item",
            "data": {
                "inventory_item_id": inventory_item_id
            }
        }
        self.network_client.send(json.dumps(message) + "\n")
        print(f"[Inventory] Equipping item {inventory_item_id}")

    def _unequip_item(self, inventory_item_id):
        """Request to unequip item"""
        message = {
            "action": "unequip_item",
            "data": {
                "inventory_item_id": inventory_item_id
            }
        }
        self.network_client.send(json.dumps(message) + "\n")
        print(f"[Inventory] Unequipping item {inventory_item_id}")

    def _drop_item(self, slot):
        """Request to drop/delete item"""
        item = self.items.get(slot)
        if not item:
            return
        
        # TODO: Add confirmation dialog
        message = {
            "action": "drop_item",
            "data": {
                "inventory_item_id": item.id
            }
        }
        self.network_client.send(json.dumps(message) + "\n")
        print(f"[Inventory] Dropping item {item.name}")

    def handle_response(self, action, data):
        """Handle inventory-related responses from server"""
        if action == "inventory_data":
            self.handle_inventory_data(data)
            # Update player's equipped weapon sprite after loading inventory
            if self.game_loop:
                self.game_loop._update_player_weapon()
        elif action == "item_moved":
            print(f"[Inventory] Item moved successfully")
            self.request_inventory()  # Refresh
        elif action == "item_equipped":
            print(f"[Inventory] Item equipped successfully")
            self.request_inventory()  # Refresh
            # Update player's equipped weapon sprite
            if self.game_loop:
                self.game_loop._update_player_weapon()
        elif action == "item_unequipped":
            print(f"[Inventory] Item unequipped successfully")
            self.request_inventory()  # Refresh
            # Update player's equipped weapon sprite
            if self.game_loop:
                self.game_loop._update_player_weapon()
        elif action == "item_dropped":
            print(f"[Inventory] Item dropped successfully")
            self.request_inventory()  # Refresh
        elif action == "item_added":
            print(f"[Inventory] Item added successfully")
            self.request_inventory()  # Refresh

    def draw(self, screen, player):
        """Draw the inventory window"""
        if not self.is_open:
            return
        
        self.resize(screen)
        screen_rect = screen.get_rect()

        # Center the window
        bg_rect = self.background.get_rect(center=screen_rect.center)
        self.bg_rect = bg_rect

        # Build gear slots after resize
        self._build_gear_slots()

        # Draw the background
        screen.blit(self.background, bg_rect)

        # Draw gear slots with equipped items
        self._draw_gear_slots(screen, bg_rect, player)

        # Draw stats
        self._draw_stats(screen, bg_rect, player)

        # Draw inventory items
        self._draw_items(screen, bg_rect)

        # Draw hover info last so it appears on top
        self._draw_hover_info(screen, bg_rect)

    def _draw_stats(self, screen, bg_rect, player):
        """Draw character stats under the gear area of the inventory"""
        small_font = pygame.font.Font(None, 35)
        medium_font = pygame.font.Font(None, 28)

        # Get scaling ratios (same as in resize)
        scale_x = bg_rect.width / self.original_bg.get_width()
        scale_y = bg_rect.height / self.original_bg.get_height()

        # Position (in the original image)
        base_x = 1600
        base_y = 600 

        # Apply scaling + position offset
        x = bg_rect.x + int(base_x * scale_x)
        y = bg_rect.y + int(base_y * scale_y)

        line_height = int(50 * scale_y)

        stats = {k.lower(): v for k, v in player.stats.items()}

        for key in ("title", "gold"):
            if key in stats:
                value = stats[key]
                label = key.capitalize()
                text = f"{label}: {value}"

                font_to_use = medium_font if key == "gold" else small_font
                color = (212, 175, 55)

                # Shadow
                shadow = font_to_use.render(text, True, (0, 0, 0))
                screen.blit(shadow, (x + 2, y + 2))

                # Text
                surf = font_to_use.render(text, True, color)
                screen.blit(surf, (x, y))
                y += line_height

    def _draw_items(self, screen, bg_rect):
        """Draw inventory items"""
        for slot_index, rect in enumerate(self.slots):
            world_rect = rect.move(bg_rect.topleft)
            
            # Skip drawing the item that is currently being dragged
            if self.dragging_slot is not None and slot_index == self.dragging_slot:
                continue

            item = self.items.get(slot_index)
            if item and item.image:
                # Draw item icon
                scale_factor = 0.8
                icon_w = int(rect.width * scale_factor)
                icon_h = int(rect.height * scale_factor)
                icon = pygame.transform.smoothscale(item.image, (icon_w, icon_h))
                screen.blit(icon, icon.get_rect(center=world_rect.center))
                
                # Draw quantity if > 1
                if item.quantity > 1:
                    qty_font = pygame.font.Font(None, 20)
                    qty_text = qty_font.render(str(item.quantity), True, (255, 255, 255))
                    qty_shadow = qty_font.render(str(item.quantity), True, (0, 0, 0))
                    screen.blit(qty_shadow, (world_rect.right - 22, world_rect.bottom - 22))
                    screen.blit(qty_text, (world_rect.right - 20, world_rect.bottom - 20))
                
                # Draw equipped indicator
                if item.is_equipped:
                    equipped_font = pygame.font.Font(None, 18)
                    equipped_text = equipped_font.render("E", True, (0, 255, 0))
                    screen.blit(equipped_text, (world_rect.left + 5, world_rect.top + 5))

        # Draw dragged item on top of mouse
        if self.dragging_item:
            mouse_x, mouse_y = pygame.mouse.get_pos()
            screen.blit(self.dragging_item, (mouse_x + self.drag_offset[0], mouse_y + self.drag_offset[1]))

    def _draw_gear_slots(self, screen, bg_rect, player):
        """Draw the gear slots and equipped items"""
        if not self.gear_slots:
            return
        
        for gear_name, rect in self.gear_slots.items():
            # Calculate world position
            world_rect = rect.move(bg_rect.topleft)
            
            # Get the server slot name
            server_slot = self.gear_to_server_slot.get(gear_name)
            if not server_slot:
                continue
            
            # Check if there's an item equipped in this slot
            equipped_item_id = self.equipped_slots.get(server_slot)
            
            if equipped_item_id:
                # Find the item in our items dict
                equipped_item = None
                for item in self.items.values():
                    if item.id == equipped_item_id:
                        equipped_item = item
                        break
                
                if equipped_item and equipped_item.image:
                    # Draw the equipped item in the gear slot
                    scale_factor = 0.7
                    icon_w = int(rect.width * scale_factor)
                    icon_h = int(rect.height * scale_factor)
                    icon = pygame.transform.smoothscale(equipped_item.image, (icon_w, icon_h))
                    screen.blit(icon, icon.get_rect(center=world_rect.center))
            else:
                # Draw empty slot indicator (optional)
                # You could draw the gear slot name or an icon
                small_font = pygame.font.Font(None, 18)
                text = small_font.render(gear_name[:3], True, (100, 100, 100))
                screen.blit(text, (world_rect.centerx - text.get_width()//2, 
                                world_rect.centery - text.get_height()//2))

    def _draw_hover_info(self, screen, bg_rect):
        """Draw tooltip when hovering over an item"""
        mouse_x, mouse_y = pygame.mouse.get_pos()

        for idx, rect in enumerate(self.slots):
            world_rect = rect.move(bg_rect.topleft)
            if world_rect.collidepoint((mouse_x, mouse_y)):
                item = self.items.get(idx)
                if not item:
                    return

                # Build tooltip lines
                lines = [
                    item.name,
                    item.description,
                    f"Grade: {item.grade}",
                ]
                
                # Add stats
                if item.stats:
                    lines.append("")  # Blank line
                    for stat_key, stat_value in item.stats.items():
                        if stat_key != "durability":
                            lines.append(f"{stat_key}: {stat_value}")
                
                # Add durability
                if item.max_durability:
                    durability_pct = int((item.current_durability / item.max_durability) * 100)
                    lines.append(f"Durability: {durability_pct}%")
                
                # Add requirements
                if item.requirements:
                    lines.append("")  # Blank line
                    lines.append("Requirements:")
                    for req_key, req_value in item.requirements.items():
                        lines.append(f"  {req_key.upper()}: {req_value}")
                
                # Add value
                if item.value > 0:
                    lines.append(f"Value: {item.value} gold")
                
                lines = [line for line in lines if line]  # Remove empty lines

                # Calculate tooltip size
                padding = 8
                spacing = 5
                font = pygame.font.Font(None, 22)
                
                text_widths = [font.size(line)[0] for line in lines]
                text_height = font.size("Test")[1]
                icon_size = 40 if item.image else 0
                
                width = max(text_widths) + icon_size + padding * 3 + spacing
                height = (text_height + 2) * len(lines) + padding * 2

                tooltip_rect = pygame.Rect(mouse_x + 20, mouse_y + 20, width, height)

                # Keep tooltip inside screen
                screen_rect = screen.get_rect()
                if tooltip_rect.right > screen_rect.right:
                    tooltip_rect.right = mouse_x - 20
                if tooltip_rect.bottom > screen_rect.bottom:
                    tooltip_rect.bottom = mouse_y - 20

                # Draw rounded background
                surf = pygame.Surface((tooltip_rect.width, tooltip_rect.height), pygame.SRCALPHA)
                pygame.draw.rect(surf, (30, 30, 30, 240), (0, 0, tooltip_rect.width, tooltip_rect.height), border_radius=8)
                pygame.draw.rect(surf, (200, 200, 200), (0, 0, tooltip_rect.width, tooltip_rect.height), 2, border_radius=8)
                screen.blit(surf, tooltip_rect.topleft)

                # Draw icon
                x_offset = tooltip_rect.x + padding
                y_offset = tooltip_rect.y + padding
                
                if item.image:
                    icon = pygame.transform.smoothscale(item.image, (icon_size, icon_size))
                    screen.blit(icon, (x_offset, y_offset))
                    x_offset += icon_size + spacing

                # Draw text
                text_x = x_offset
                for i, line in enumerate(lines):
                    # Color based on content
                    color = (255, 255, 255)
                    if i == 0:  # Name
                        color = self._get_grade_color(item.grade)
                    elif "Requirements:" in line or line.startswith("  "):
                        color = (255, 200, 100)
                    
                    text_surf = font.render(line, True, color)
                    screen.blit(text_surf, (text_x, y_offset))
                    y_offset += text_height + 2
                
                break

    def _get_grade_color(self, grade):
        """Get color for item grade"""
        colors = {
            "Common": (255, 255, 255),
            "Uncommon": (100, 255, 100),
            "Rare": (100, 150, 255),
            "Epic": (200, 100, 255),
            "Legendary": (255, 150, 50),
        }
        return colors.get(grade, (255, 255, 255))