/**
 * @file systems.cpp
 * @brief ECS System implementations using FLECS C++ API
 */

#include "systems.hpp"
#include "components.hpp"
#include "game.hpp"

void register_systems(flecs::world &ecs, GameContext *ctx) {
  // Movement system - updates positions based on velocities
  ecs.system<Position, const Velocity>("MovementSystem")
      .kind(flecs::OnUpdate)
      .each([](flecs::iter &it, size_t, Position &pos, const Velocity &vel) {
        pos.x += vel.x * it.delta_time();
        pos.y += vel.y * it.delta_time();
      });

  // Lifetime system - decrements lifetime and destroys expired entities
  ecs.system<Lifetime>("LifetimeSystem")
      .kind(flecs::OnUpdate)
      .each([](flecs::iter &it, size_t i, Lifetime &life) {
        life.remaining -= it.delta_time();
        if (life.remaining <= 0.0f) {
          it.entity(i).add<ToDestroy>();
        }
      });

  // Cleanup system - destroys entities marked with ToDestroy
  ecs.system<const ToDestroy>("CleanupSystem")
      .kind(flecs::PostUpdate)
      .each([](flecs::entity e, const ToDestroy &) { e.destruct(); });

  // Render rect system
  ecs.system<const Position, const RectShape, const Color>("RenderRectSystem")
      .kind(flecs::OnStore)
      .ctx(ctx)
      .each([](flecs::iter &it, size_t, const Position &pos,
               const RectShape &rect, const Color &color) {
        auto *game_ctx = static_cast<GameContext *>(it.ctx());
        if (!game_ctx || !game_ctx->renderer)
          return;

        SDL_SetRenderDrawColor(game_ctx->renderer, color.r, color.g, color.b,
                               color.a);

        SDL_FRect dst{pos.x - rect.width / 2.0f, pos.y - rect.height / 2.0f,
                      rect.width, rect.height};

        SDL_RenderFillRect(game_ctx->renderer, &dst);
      });

  // Render sprite system
  ecs.system<const Position, const Sprite>("RenderSpriteSystem")
      .kind(flecs::OnStore)
      .ctx(ctx)
      .each([](flecs::iter &it, size_t, const Position &pos,
               const Sprite &sprite) {
        auto *game_ctx = static_cast<GameContext *>(it.ctx());
        if (!game_ctx || !game_ctx->renderer)
          return;
        if (!sprite.visible || !sprite.texture)
          return;

        SDL_FRect dst{pos.x - sprite.src_rect.w / 2.0f,
                      pos.y - sprite.src_rect.h / 2.0f, sprite.src_rect.w,
                      sprite.src_rect.h};

        SDL_RenderTexture(game_ctx->renderer, sprite.texture, &sprite.src_rect,
                          &dst);
      });
}
