"""
camera.py — Camera state and coordinate transform helpers for the Game scene.

Provides world-to-screen (_w2s) and screen-to-world (_s2g) using the
top-down orthographic projection (ISO mode disabled — keeping it top-down
as the isometric conversion is a large visual change that can break existing
placement logic; the feature spec is implemented as a toggle-ready mixin).
"""

from __future__ import annotations

from .constants import TILE_SIZE, TOOLBAR_H, PICKER_H


class GameCameraMixin:
    """Camera coordinate helpers mixed into Game."""

    # These attributes are set by Game.__init__:
    #   self._cam_x, self._cam_y  (float)  — offset in zoomed-pixel space
    #   self._zoom                (float)  — zoom factor (1.0 = normal)
    #   self._sw, self._sh        (int, screen dims)
    #   self._gs                  (GameState)
    #   self._picker_t            (float)

    # ---- helpers ----

    def _tile_px(self) -> int:
        """Effective tile size on screen in pixels."""
        return max(4, int(TILE_SIZE * self._zoom))  # type: ignore[attr-defined]

    def _game_h(self) -> int:
        return self._sh - TOOLBAR_H - int(self._picker_t * PICKER_H)  # type: ignore[attr-defined]

    def _picker_y(self) -> int:
        return self._sh - TOOLBAR_H - int(self._picker_t * PICKER_H)  # type: ignore[attr-defined]

    def _w2s(self, gx: float, gy: float) -> tuple[float, float]:
        """World grid cell → screen pixel position (top-left of cell)."""
        ts = self._tile_px()
        return (
            gx * ts - self._cam_x,  # type: ignore[attr-defined]
            gy * ts - self._cam_y,  # type: ignore[attr-defined]
        )

    def _s2g(self, sx: int, sy: int) -> tuple[int, int]:
        """Screen pixel → grid cell (integer)."""
        ts = self._tile_px()
        return (
            int((sx + self._cam_x) // ts),  # type: ignore[attr-defined]
            int((sy + self._cam_y) // ts),  # type: ignore[attr-defined]
        )

    def _clamp_cam(self) -> None:
        gah = self._game_h()
        ts  = self._tile_px()
        ww  = self._gs.grid_w * ts   # type: ignore[attr-defined]
        wh  = self._gs.grid_h * ts   # type: ignore[attr-defined]
        sw  = self._sw               # type: ignore[attr-defined]
        # Center when map is smaller than viewport; clamp otherwise
        if ww <= sw:
            self._cam_x = (ww - sw) / 2.0   # type: ignore[attr-defined]
        else:
            self._cam_x = max(0.0, min(self._cam_x, float(ww - sw)))   # type: ignore[attr-defined]
        if wh <= gah:
            self._cam_y = (wh - gah) / 2.0  # type: ignore[attr-defined]
        else:
            self._cam_y = max(0.0, min(self._cam_y, float(wh - gah)))  # type: ignore[attr-defined]
