"""
world_gen.py — World generation and level-up expansion for the Game scene.
"""

from __future__ import annotations

import random
from typing import TYPE_CHECKING

from helpers.game_data import BUILDING_TYPES

if TYPE_CHECKING:
    from helpers.game_data import GameState
    from helpers.world_data import WorldMeta


class GameWorldGenMixin:
    """World generation logic mixed into Game."""

    def _world_gen(self) -> None:
        seed = getattr(self._meta, "seed", 0) or 1  # type: ignore[attr-defined]
        rng  = random.Random(seed)
        gs   = self._gs  # type: ignore[attr-defined]
        world_level = gs.level()

        # Residential clusters (always spawn bungalows and houses)
        for _ in range(rng.randint(4, 7)):
            cx = rng.randint(6, gs.grid_w - 10)
            cy = rng.randint(6, gs.grid_h - 10)
            for _ in range(rng.randint(3, 7)):
                self._try_place_near(rng, "bungalow", cx, cy, 6)
            for _ in range(rng.randint(1, 3)):
                self._try_place_near(rng, "house", cx, cy, 6)
            # multifamily only at level 3+
            if world_level >= 3 and rng.random() > 0.45:
                self._try_place_near(rng, "multifamily", cx, cy, 5)

        # Industrial clusters — only spawn types appropriate to current level
        for _ in range(rng.randint(2, 4)):
            cx = rng.randint(6, gs.grid_w - 10)
            cy = rng.randint(6, gs.grid_h - 10)
            # small_factory: level 2+
            if world_level >= 2:
                for _ in range(rng.randint(2, 4)):
                    self._try_place_near(rng, "small_factory", cx, cy, 5)
            # warehouse: level 3+
            if world_level >= 3:
                for _ in range(rng.randint(1, 2)):
                    self._try_place_near(rng, "warehouse", cx, cy, 5)
            # factory: level 5+
            if world_level >= 5 and rng.random() > 0.4:
                self._try_place_near(rng, "factory", cx, cy, 4)
            # big_factory: level 6+
            if world_level >= 6 and rng.random() > 0.65:
                self._try_place_near(rng, "big_factory", cx, cy, 4)

    def _try_place_near(self, rng: random.Random, type_id: str,
                        cx: int, cy: int, radius: int,
                        attempts: int = 25) -> None:
        td = BUILDING_TYPES.get(type_id)
        if td is None:
            return
        gs: GameState = self._gs  # type: ignore[attr-defined]
        for _ in range(attempts):
            gx = max(0, min(cx + rng.randint(-radius, radius),
                            gs.grid_w - td.size[0]))
            gy = max(0, min(cy + rng.randint(-radius, radius),
                            gs.grid_h - td.size[1]))
            b = gs.place_building(type_id, gx, gy)
            if b is not None:
                return

    def _expand_world_for_level(self, level: int) -> None:
        """Spawn additional consumer buildings when a new level is reached."""
        meta: WorldMeta = self._meta  # type: ignore[attr-defined]
        seed = (getattr(meta, "seed", 0) or 1) + level * 1000
        rng  = random.Random(seed)
        gs: GameState = self._gs  # type: ignore[attr-defined]

        # Base residential expansion each level
        cx = rng.randint(8, gs.grid_w - 12)
        cy = rng.randint(8, gs.grid_h - 12)
        for _ in range(rng.randint(2, 5)):
            self._try_place_near(rng, "bungalow", cx, cy, 7)
        for _ in range(rng.randint(1, 3)):
            self._try_place_near(rng, "house", cx, cy, 7)

        # Higher-level consumer types
        if level >= 2:
            for _ in range(rng.randint(1, 3)):
                self._try_place_near(rng, "small_factory", cx, cy, 6)
        if level >= 3:
            for _ in range(rng.randint(1, 2)):
                self._try_place_near(rng, "multifamily", cx, cy, 5)
        if level >= 3:
            for _ in range(rng.randint(1, 2)):
                self._try_place_near(rng, "warehouse", cx, cy, 5)
        if level >= 5:
            if rng.random() > 0.4:
                self._try_place_near(rng, "factory", cx, cy, 4)
        if level >= 6:
            if rng.random() > 0.5:
                self._try_place_near(rng, "big_factory", cx, cy, 4)
