// src/game/obstacle_system.h
#pragma once
#include "obstacle_manager.h"
#include "../render/player_positioning.h"
#include "../assets/obstacle_crawl_frames.h"
#include "collision.h"
#include "mbed.h"

inline int clamp_min(int a, int b) { return (a > b) ? a : b; }
inline int clamp_max(int a, int b) { return (a < b) ? a : b; }

// Handles spawning, movement, rendering, and collision of obstacles
class ObstacleSystem {
public:
    ObstacleSystem() : tick_counter_(0), spawn_index_(0) {}

    // Called once per frame
    bool update_and_draw(const CharacterPosition &player_pos,
                         MovementType player_movement) {
        // Update timers, move existing obstacles
        tick_counter_++;
        if (tick_counter_ % UPDATE_INTERVAL == 0) {
            update_obstacles(1);
        }

        // Periodically spawn new obstacle
        if (tick_counter_ % SPAWN_EVERY_TICKS == 0) {
            auto type = (spawn_index_++ % 2 == 0) ? CrawlObstacleType::Crawl1 : CrawlObstacleType::Crawl2;
            const int w = (type == CrawlObstacleType::Crawl1) ? OBSTACLE_CRAWL1_FRAME_WIDTH : OBSTACLE_CRAWL2_FRAME_WIDTH;
            spawn_obstacle(type, VIEW_WIDTH - w - 1);
        }

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

            const char **frame = nullptr;
            int height = 0;
            if (obstacle_pool[i].type == CrawlObstacleType::Crawl1) {
                frame = OBSTACLE_CRAWL1_FRAME;
                height = OBSTACLE_CRAWL1_FRAME_HEIGHT;
            } else {
                frame = OBSTACLE_CRAWL2_FRAME;
                height = OBSTACLE_CRAWL2_FRAME_HEIGHT;
            }

            draw_clipped_obstacle(obstacle_pool[i], frame, height);

            // Collision check
            if (check_collision(player_pos, player_movement,
                                obstacle_pool[i].data)) {
                printf("\033[2J\033[H");
                printf("GAME OVER\r\n");
                return true;
            }
        }

        return false;
    }

private:
    static constexpr int SPAWN_EVERY_TICKS = 35;
    static constexpr int UPDATE_INTERVAL = 1; // move obstacles each frame
    int tick_counter_;
    int spawn_index_;

    static void draw_clipped_obstacle(const MovingObstacle &obs,
                                      const char ** /*frame*/,
                                      int /*frame_height*/) {
        draw_obstacle(obs.data.x, obs.data.y, obs.type);
    }
};
