"""AutoPOE2 - Skill & Action Bar Geometry and Constants.

Định nghĩa hình học Action Bar, Pop-up Skill menu và tỷ lệ tọa độ đa độ phân giải.
Tuân thủ Rule 1, Rule 4 (Kiến trúc Module Hóa), Rule 7 (Chuẩn người chơi thật).
"""

from __future__ import annotations

from dataclasses import dataclass
from enum import Enum
from typing import Dict, Tuple


class ActionBarSlot(str, Enum):
    """Danh mục các phím tắt kỹ năng trên thanh Action Bar của POE2."""
    SLOT_Q = "Q"
    SLOT_E = "E"
    SLOT_R = "R"
    SLOT_T = "T"
    SLOT_F = "F"
    SLOT_RMB = "RMB"
    SLOT_LMB = "LMB"
    SLOT_MMB = "MMB"


@dataclass(frozen=True)
class NormalizedSlotCoord:
    """Tọa độ chuẩn hóa [0.0, 1.0] theo kích thước Client Area (width, height)."""
    norm_x: float
    norm_y: float

    def to_client_pixels(self, client_w: int, client_h: int) -> Tuple[int, int]:
        """Quy đổi tọa độ chuẩn hóa thành tọa độ pixel thực tế trong client area."""
        return int(round(self.norm_x * client_w)), int(round(self.norm_y * client_h))


# Tọa độ chuẩn hóa các ô Action Bar theo tỷ lệ chuẩn POE2 UI (đo đạc thực tế 1189x891 và 2560x1440)
# Tại 1189x891:
# Q: (795, 860)  -> 795/1189  = ~0.6686, 860/891 = ~0.9652
# E: (840, 860)  -> 840/1189  = ~0.7065, 860/891 = ~0.9652
# R: (885, 860)  -> 885/1189  = ~0.7443, 860/891 = ~0.9652
# T: (930, 860)  -> 930/1189  = ~0.7822, 860/891 = ~0.9652
# F: (975, 860)  -> 975/1189  = ~0.8200, 860/891 = ~0.9652
# RMB: (1030, 860) -> 1030/1189 = ~0.8663, 860/891 = ~0.9652
ACTION_BAR_DEFAULT_OFFSETS: Dict[ActionBarSlot, NormalizedSlotCoord] = {
    ActionBarSlot.SLOT_Q: NormalizedSlotCoord(norm_x=0.6686, norm_y=0.9652),
    ActionBarSlot.SLOT_E: NormalizedSlotCoord(norm_x=0.7065, norm_y=0.9652),
    ActionBarSlot.SLOT_R: NormalizedSlotCoord(norm_x=0.7443, norm_y=0.9652),
    ActionBarSlot.SLOT_T: NormalizedSlotCoord(norm_x=0.7822, norm_y=0.9652),
    ActionBarSlot.SLOT_F: NormalizedSlotCoord(norm_x=0.8200, norm_y=0.9652),
    ActionBarSlot.SLOT_RMB: NormalizedSlotCoord(norm_x=0.8663, norm_y=0.9652),
}


@dataclass(frozen=True)
class SkillPopupGeometry:
    """Thông số hình học của Pop-up Menu ACTIONS / SKILLS / GEM SKILLS."""
    # Chiều rộng và chiều cao popup theo tỷ lệ client area (hiệu chuẩn từ dữ liệu thật 1189x891)
    width_ratio: float = 0.2035      # 242px / 1189
    height_ratio: float = 0.3311     # 295px / 891
    margin_bottom_ratio: float = 0.0224  # Khoảng cách từ đáy popup tới ô slot (20px / 891)

    # Tọa độ tương đối bên trong popup [0.0..1.0]:
    # Nút Close [X] ở góc trên bên phải
    close_btn_rel_x: float = 0.9628
    close_btn_rel_y: float = 0.0441

    # Mục ACTIONS -> Clear / Unbind (dấu X to)
    unbind_rel_x: float = 0.50
    unbind_rel_y: float = 0.2203

    # Mục SKILLS (hàng kỹ năng vũ khí gồm 3 ô)
    skills_row_rel_y: float = 0.4915
    skills_col_rel_x: Tuple[float, ...] = (0.186, 0.413, 0.640)

    # Mục GEM SKILLS (lưới kỹ năng ngọc 4 cột x N hàng)
    gem_skills_start_rel_y: float = 0.7797
    gem_skills_row_spacing_ratio: float = 0.1864
    gem_skills_col_rel_x: Tuple[float, ...] = (0.120, 0.343, 0.566, 0.789)


SKILL_POPUP_GEOMETRY = SkillPopupGeometry()


def get_slot_client_pos(slot: ActionBarSlot, client_w: int, client_h: int) -> Tuple[int, int]:
    """Tính toán tọa độ pixel (x, y) của ô slot trên Action Bar theo kích thước Client Area."""
    coord = ACTION_BAR_DEFAULT_OFFSETS.get(slot)
    if not coord:
        raise ValueError(f"Không tìm thấy cấu hình hình học cho slot: {slot}")
    return coord.to_client_pixels(client_w, client_h)


def get_popup_bounding_box(
    slot: ActionBarSlot,
    client_w: int,
    client_h: int,
    geo: SkillPopupGeometry = SKILL_POPUP_GEOMETRY,
) -> Tuple[int, int, int, int]:
    """Tính toán bounding box (left, top, right, bottom) của Pop-up Menu khi bật từ slot."""
    slot_x, slot_y = get_slot_client_pos(slot, client_w, client_h)
    pw = int(round(geo.width_ratio * client_w))
    ph = int(round(geo.height_ratio * client_h))
    margin_b = int(round(geo.margin_bottom_ratio * client_h))

    # Căn giữa popup theo trục X của slot, nhưng không tràn ra ngoài mép phải màn hình
    left = slot_x - pw // 2
    if left + pw > client_w - 5:
        left = client_w - pw - 5
    if left < 5:
        left = 5

    bottom = slot_y - margin_b
    top = bottom - ph
    right = left + pw
    return left, top, right, bottom
