#include "debug_overlay.h"

#include <frostbite2D/graphics/renderer.h>

namespace ns_game {

namespace {

void drawRect(const frostbite2D::Rect& rect, const frostbite2D::Color& color) {
  frostbite2D::Renderer::get().drawQuad(rect, color);
}

void drawOutline(const frostbite2D::Rect& rect, const frostbite2D::Color& color,
                 float thickness = 2.0f) {
  drawRect(frostbite2D::Rect(rect.left(), rect.top(), rect.width(), thickness),
           color);
  drawRect(frostbite2D::Rect(rect.left(), rect.bottom() - thickness,
                             rect.width(), thickness),
           color);
  drawRect(frostbite2D::Rect(rect.left(), rect.top(), thickness, rect.height()),
           color);
  drawRect(frostbite2D::Rect(rect.right() - thickness, rect.top(), thickness,
                             rect.height()),
           color);
}

void drawCross(const frostbite2D::Vec2& position,
               const frostbite2D::Color& color) {
  constexpr float kSize = 18.0f;
  constexpr float kThickness = 3.0f;
  drawRect(frostbite2D::Rect(position.x - kSize * 0.5f,
                             position.y - kThickness * 0.5f, kSize,
                             kThickness),
           color);
  drawRect(frostbite2D::Rect(position.x - kThickness * 0.5f,
                             position.y - kSize * 0.5f, kThickness, kSize),
           color);
}

BattleZoneDebugState resolveZoneState(
    size_t zoneIndex, const std::vector<BattleZoneDebugInfo>* debugInfo) {
  if (!debugInfo) {
    return BattleZoneDebugState::Idle;
  }

  for (const BattleZoneDebugInfo& info : *debugInfo) {
    if (info.zoneIndex == zoneIndex) {
      return info.state;
    }
  }
  return BattleZoneDebugState::Idle;
}

frostbite2D::Color zoneColor(BattleZoneDebugState state) {
  switch (state) {
    case BattleZoneDebugState::Active:
      return frostbite2D::Color(1.0f, 0.82f, 0.15f, 0.95f);
    case BattleZoneDebugState::Cleared:
      return frostbite2D::Color(0.45f, 0.48f, 0.52f, 0.65f);
    case BattleZoneDebugState::Idle:
    default:
      return frostbite2D::Color(0.95f, 0.25f, 0.25f, 0.9f);
  }
}

} // namespace

void DebugOverlay::Render(const LevelDefinition& level, const DebugFlags& flags,
                          const frostbite2D::Rect* playerBounds,
                          const std::vector<BattleZoneDebugInfo>*
                              battleZoneDebug) const {
  if (!flags.enabled) {
    return;
  }

  if (flags.showCollision) {
    drawCollision(level);
  }
  if (flags.showBattleZones) {
    drawBattleZones(level, battleZoneDebug);
  }
  if (flags.showSpawnPoints) {
    drawSpawnPoints(level);
  }
  if (flags.showActorBounds && playerBounds) {
    drawActorBounds(*playerBounds);
  }
}

void DebugOverlay::drawCollision(const LevelDefinition& level) const {
  for (const auto& platform : level.collision.platforms) {
    drawOutline(platform, frostbite2D::Color(0.1f, 0.95f, 0.45f, 0.85f));
  }
}

void DebugOverlay::drawActorBounds(const frostbite2D::Rect& bounds) const {
  drawOutline(bounds, frostbite2D::Color(1.0f, 0.78f, 0.1f, 0.9f));
}

void DebugOverlay::drawBattleZones(
    const LevelDefinition& level,
    const std::vector<BattleZoneDebugInfo>* battleZoneDebug) const {
  for (size_t i = 0; i < level.battleZones.size(); ++i) {
    const BattleZoneDefinition& zone = level.battleZones[i];
    drawOutline(zone.trigger, zoneColor(resolveZoneState(i, battleZoneDebug)),
                3.0f);
    drawOutline(zone.cameraBounds,
                frostbite2D::Color(0.25f, 0.55f, 1.0f, 0.75f), 2.0f);
  }
}

void DebugOverlay::drawSpawnPoints(const LevelDefinition& level) const {
  for (const BattleZoneDefinition& zone : level.battleZones) {
    for (const SpawnPoint& spawn : zone.enemySpawns) {
      drawCross(spawn.position, frostbite2D::Color(1.0f, 0.2f, 0.9f, 0.95f));
    }
  }
}

} // namespace ns_game
