// src/render/loop.cpp
#include "loop.h"
#include "../assets/background_frame.h"
#include "player_positioning.h"
#include "background.h"
#include "mbed.h"
#include "player.h"
#include "background.h"
#include "../game/state.h"
#include "../game/animation.h"
#include "../game/collision.h"
#include "../hardware/button.h"
#include "../render/player.h"
#include "../render/obstacle.h"
#include "../timing/speed_controller.h"
#include "../timing/movement_controller.h"
#include "../game/obstacle_system.h"

extern DigitalOut led;

// Constants
// constexpr int PLAYER_X = 9;
constexpr int PLAYER_X = 29;
constexpr int PLAYER_Y = 6;

void render_loop(int speed) {
  MovementState player_state;
  AnimationController animation;
  ButtonHandler button;
  MovementController mover(PLAYER_X, VIEW_WIDTH);
  SpeedController timing;
  timing.set_ground_speed(speed);

  CharacterPosition pos = {PLAYER_X, PLAYER_Y};

  const char *bg_file = "background_dark_inverted.txt";
  bool need_redraw = false;

  int anim_tick_counter = 0;
  int tick_counter = 0;
  int player_speed = 6;
  bool game_over = false;

  player_state.set_state(PlayerState::Walk);

  CrawlObstacleType type = CrawlObstacleType::Crawl1;
  int start_x = VIEW_WIDTH + 10;
  spawn_obstacle(type, start_x);

  Timer spawn_timer;
  spawn_timer.start();

  while (!game_over) {
    tick_counter++;

    mover.update_position(player_speed, timing.get_ground_speed());
    pos.x = mover.get_position();

    if (spawn_timer.elapsed_time() > 2s) {
      spawn_timer.reset();
      CrawlObstacleType s_type = CrawlObstacleType::Crawl1;
      int spawn_x = VIEW_WIDTH;
      int idx = spawn_obstacle(s_type, spawn_x);
      if (idx >= 0) {
        obstacle_pool[idx].active = true;
      }
    }

    need_redraw = false;
    ButtonEvent button_event = button.poll();

    if (button_event == ButtonEvent::Pressed) {
      PlayerState current = player_state.get_state();

      if (current == PlayerState::Walk || current == PlayerState::Run) {
        player_state.start_crawl(PlayerState::Crawl1);
      } else if (current == PlayerState::Crawl1) {
        player_state.start_crawl(PlayerState::Crawl2);
      }

      need_redraw = true;
    }

    // Check if crawl duration expired
    player_state.update();

    if (animation.tick(speed)) {
      anim_tick_counter++;
      int ground_speed = timing.get_ground_speed();
      for (int i = 0; i < MAX_OBSTACLES; i++) {
        if (obstacle_pool[i].active) {
          obstacle_pool[i].data.x -= ground_speed;
          // deactivate when offscreen
          if (obstacle_pool[i].data.x + obstacle_pool[i].data.width < 0)
            obstacle_pool[i].active = false;
        }
      }

      need_redraw = true;
    }

    if (need_redraw) {
      player_state.toggle_walk_frame(player_speed, anim_tick_counter);
      draw_mask(bg_file, animation.get_shift());
      FrameSelection frame = player_state.get_frame_selection();

      CharacterPosition draw_pos = get_aligned_frame_position(pos, frame.movement, frame.frame_index);
      draw_character(draw_pos.x, draw_pos.y, frame.movement, frame.frame_index);

      // for (int i = 0; i < MAX_OBSTACLES; i++) {
      //   if (!obstacle_pool[i].active)
      //     continue;

      //   draw_obstacle(obstacle_pool[i].data.x, obstacle_pool[i].data.y,
      //                 obstacle_pool[i].type);

      //   if (check_collision(pos, frame.movement, obstacle_pool[i].data)) {
      //     printf("\033[2J\033[H");
      //     printf("GAME OVER\r\n");
      //     game_over = true;
      //     break;
      //   }
      // }

      if (game_over)
	      break;

      ThisThread::sleep_for(50ms);
    }

    ThisThread::sleep_for(25ms);
  }
}
