import random


class Ball:
    """The pong ball with physics and optional trail."""

    def __init__(self, speed=1.0, max_speed=2.5, speed_increment=0.08,
                 char="O", trail=False, trail_length=4, trail_chars=None):
        self.x = 0.0
        self.y = 0.0
        self.dx = 0.0
        self.dy = 0.0
        self.speed = speed
        self.default_speed = speed
        self.max_speed = max_speed
        self.speed_increment = speed_increment
        self.char = char
        self.court_width = 0
        self.court_height = 0

        # Trail
        self.trail_enabled = trail
        self.trail_length = trail_length
        self.trail = []
        self.trail_chars = trail_chars or ['.', '.', 'o', 'o']

        # Movement accumulator
        self._move_accum = 0.0

        # Countdown before launch
        self.frozen = True
        self._freeze_time = 0.0

    def setup(self, court_width, court_height):
        """Initialize ball for given court size."""
        self.court_width = court_width
        self.court_height = court_height
        self.reset()

    def reset(self, direction=None):
        """Reset ball to center."""
        self.x = float(self.court_width // 2)
        self.y = float(self.court_height // 2)
        self.speed = self.default_speed
        self._move_accum = 0.0
        self.trail = []

        if direction is None:
            direction = random.choice([-1, 1])
        self.dx = float(direction)
        self.dy = random.uniform(-0.5, 0.5)

        self.frozen = True
        self._freeze_time = 3.0

    def update(self, dt):
        """Update ball position. Returns list of positions stepped through."""
        if self.frozen:
            self._freeze_time -= dt
            if self._freeze_time <= 0:
                self.frozen = False
            return []

        self._move_accum += self.speed
        positions = []

        while self._move_accum >= 1.0:
            self._move_accum -= 1.0

            # Record trail
            if self.trail_enabled:
                self.trail.append((self.x, self.y))
                if len(self.trail) > self.trail_length:
                    self.trail.pop(0)

            self.x += self.dx
            self.y += self.dy
            positions.append((self.x, self.y))

        return positions

    def get_display_pos(self):
        """Get integer display position, clamped to safe zone."""
        bx = int(round(self.x))
        by = int(round(self.y))
        by = max(1, min(self.court_height - 2, by))
        return bx, by

    def get_trail_positions(self):
        """Get trail display positions."""
        positions = []
        for i, (tx, ty) in enumerate(self.trail):
            txi = int(round(tx))
            tyi = int(round(ty))
            tyi = max(1, min(self.court_height - 2, tyi))
            idx = min(i, len(self.trail_chars) - 1)
            positions.append((txi, tyi, self.trail_chars[idx]))
        return positions