import { MAX_PADDLE_REFLECTION_ANGLE, MIN_PADDLE_REFLECTION_ANGLE, PADDLE_SECTOR_AMOUNT } from '../../config';
import { Game } from '../../game';
import { processBall } from '../processBall/processBall';
import { processBrickCollision } from '../processBrickCollision/processBrickCollision';
import { processReflection } from '../processReflection/processReflection';
import { updatePerks } from '../updatePerks/updatePerks';

/**
 * Функция для вычисления взаимодействий сущностей игры в зависимости от времени из Ticker
 * @param {Game} game экземпляр класса игры
 * @param {number} containerWidth ширина игрового контейнера в пикселях
 * @param {number} containerHeight высота игрового контейнера в пикселях
 * @param {number} deltaTime изменение времени из Ticker
 */
export function tick(game, containerWidth, containerHeight, deltaTime) {
  try {
    if (!(game instanceof Game)) {
      throw new Error('Аргумент game должен быть экземпляром класса игры');
    }

    if ([containerWidth, containerHeight].some((element) => typeof element !== 'number')) {
      throw new Error('Значения размеров игрового контейнера должены являться числами');
    }

    if (containerWidth <= 0 || containerHeight <= 0) {
      throw new Error('Размеры игрового контейнера должены быть положительными числами');
    }

    if (typeof deltaTime !== 'number' || deltaTime <= 0) {
      throw new Error('Значение изменения времени должно быть положительным числом');
    }

    const { paddle } = game;

    // Бонусы падают и ловятся ракеткой каждый кадр
    updatePerks(game, containerHeight, deltaTime);

    for (const ball of game.balls) {
      ball.moveForward(deltaTime);
      // Проверка столкновения со стенами и вылета за границу поля снизу
      const hitWallOrWentOut = processBall(ball, containerWidth, containerHeight);

      if (hitWallOrWentOut) {
        continue;
      }

      // Проверка столкновения с кирпичами
      const hitBrick = processBrickCollision(game, ball);

      if (hitBrick) {
        continue;
      }

      // Взаимодействие мяча и ракетки - обновление горизонтальной и вертикальной скорости в зависимости от сектора попадания
      processReflection(
        paddle,
        ball,
        PADDLE_SECTOR_AMOUNT,
        MIN_PADDLE_REFLECTION_ANGLE,
        MAX_PADDLE_REFLECTION_ANGLE,
        ball.speed,
      );
    }
  } catch (err) {
    console.error(err);
    return null;
  }
}
