"""
Shared 2.5D Isometric Coordinate and Mathematical System for FreeExile (Server Core).
Implements standard 2:1 isometric projection, reverse projection (raycasting),
height layering, and hardware depth value calculations.
"""

import math
from typing import Tuple, NamedTuple


class Vector2D(NamedTuple):
    x: float
    y: float


class Vector3D(NamedTuple):
    x: float
    y: float
    z: float


class IsometricMath:
    # Standard 2:1 isometric projection parameters
    TILE_WIDTH: float = 64.0
    TILE_HEIGHT: float = 32.0
    HEIGHT_SCALE: float = 24.0  # Visual pixel elevation per 1.0 unit of world Z
    CAPSULE_HEIGHT: float = 1.8  # Standard character height for Z-collision

    @staticmethod
    def world_to_screen(world_x: float, world_y: float, world_z: float = 0.0) -> Vector2D:
        """
        Converts 2.5D world coordinates (X, Y ground plane, Z elevation)
        to 2D isometric screen projection coordinates.
        """
        screen_x = (world_x - world_y) * (IsometricMath.TILE_WIDTH / 2.0)
        screen_y = (world_x + world_y) * (IsometricMath.TILE_HEIGHT / 2.0) - (world_z * IsometricMath.HEIGHT_SCALE)
        return Vector2D(screen_x, screen_y)

    @staticmethod
    def screen_to_world(screen_x: float, screen_y: float, world_z: float = 0.0) -> Vector2D:
        """
        Reverse projection: maps 2D screen coordinates back to 2.5D world coordinates on plane Z.
        Used for touch raycasting and ground target aiming.
        """
        adjusted_y = screen_y + (world_z * IsometricMath.HEIGHT_SCALE)
        world_x = (screen_x / IsometricMath.TILE_WIDTH) + (adjusted_y / IsometricMath.TILE_HEIGHT)
        world_y = (adjusted_y / IsometricMath.TILE_HEIGHT) - (screen_x / IsometricMath.TILE_WIDTH)
        return Vector2D(world_x, world_y)

    @staticmethod
    def calculate_depth_key(world_y: float, world_z: float = 0.0, layer_offset: float = 0.0) -> float:
        """
        Calculates a monotonic depth sorting key for hardware Z-buffer.
        In 2.5D isometric view, objects with larger Y coordinates are rendered in front (closer to camera).
        """
        return (world_y * 10.0) + world_z + layer_offset

    @staticmethod
    def check_height_overlap(z_a: float, z_b: float, threshold: float = CAPSULE_HEIGHT) -> bool:
        """
        Determines whether two entities occupy the same vertical slice for collision.
        Allows characters on bridges (Z=1.0) to walk over characters underneath (Z=0.0).
        """
        return abs(z_a - z_b) < threshold

    @staticmethod
    def distance_2d(x1: float, y1: float, x2: float, y2: float) -> float:
        return math.hypot(x2 - x1, y2 - y1)
