#include "gui/boss_fight_ui.hpp"
#include "easings.hpp"
#include "sound.hpp"
#include <fmt/xchar.h>

namespace gui {
  using namespace guecs;

  BossFightUI::BossFightUI(shared_ptr<DinkyECS::World> world, DinkyECS::Entity boss_id)
    : $world(world),
      $boss_id(boss_id),
      $config(world->get_the<components::GameConfig>())
  {
    $status.position(0, 0, BOSS_VIEW_X, SCREEN_HEIGHT);
    $status.layout(
        "[main_status]"
        "[=status_3|=status_4]"
        "[=status_5|=status_6]"
        "[=status_7|=status_8]");

    $overlay.position(BOSS_VIEW_X, BOSS_VIEW_Y,
        BOSS_VIEW_WIDTH, BOSS_VIEW_HEIGHT);

    $overlay.layout("[=overlay_1|=overlay_2|=overlay_4]"
      "[=overlay_5|=overlay_6|=overlay_8]"
      "[=overlay_9|=overlay_10|=overlay_12]"
      "[=overlay_13|=overlay_14|=overlay_16]");

    $sounds = $world->get<components::Sound>($boss_id);
    $combat = $world->get<components::Combat>($boss_id);
  }

  void BossFightUI::configure_sprite() {
    $sprite_config = $world->get<components::Sprite>($boss_id);
    $animation = $world->get<components::Animation>($boss_id);
    $animation.frame_width = $sprite_config.width;

    $boss_image = textures::get_sprite($sprite_config.name);
    sf::IntRect frame_rect{{0,0},{$sprite_config.width,$sprite_config.height}};
    $boss_image.sprite->setTextureRect(frame_rect);
    $boss_image.sprite->setScale({$sprite_config.scale, $sprite_config.scale});

    auto bounds = $boss_image.sprite->getLocalBounds();
    auto bg_bounds = $boss_background.sprite->getLocalBounds();
    float x_diff = bg_bounds.size.x / 2;

    $boss_pos = {float(BOSS_VIEW_X) + x_diff, bounds.size.y / 2};
    $boss_image.sprite->setOrigin({bounds.size.x / 2, bounds.size.y / 2});
    $boss_image.sprite->setPosition($boss_pos);
  }

  void BossFightUI::configure_background() {
    auto& boss = $world->get<components::BossFight>($boss_id);

    $boss_background = textures::get_sprite(boss.background);
    $boss_background.sprite->setPosition({BOSS_VIEW_X, BOSS_VIEW_Y});
    $status.set<Background>($status.MAIN, {$status.$parser});

    if(boss.stage) {
      $boss_has_stage = true;
      $boss_stage = textures::get_sprite(*boss.stage);
      $boss_stage.sprite->setPosition({BOSS_VIEW_X, BOSS_VIEW_Y});
    }
  }

  void BossFightUI::configure_gui() {
    for(auto& [name, cell] : $status.cells()) {
      auto button = $status.entity(name);
      $status.set<Rectangle>(button, {});
      $status.set<Clickable>(button, {
          [this, name](auto, auto){
            dbc::log(fmt::format("STATUS: {}", name));
          }
      });
      if(name == "main_status") {
        $status.set<Text>(button, {fmt::format(L"HP: {}", $combat.hp)});
      } else {
        $status.set<Text>(button, {L"Attack"});
      }
    }
    $status.init();

    for(auto& [name, cell] : $overlay.cells()) {
      auto region = $overlay.entity(name);
      $overlay.set<Clickable>(region, {
          [this, name](auto, auto){
            dbc::log(fmt::format("OVERLAY: {}", name));
          }
      });
    }

    $overlay.init();
  }

  void BossFightUI::init() {
    // background must come first
    configure_background();
    configure_sprite();
    configure_gui();
  }

  void BossFightUI::bounce_boss(sf::RenderWindow& window) {
    sf::IntRect frame_rect{{0,0},{$sprite_config.width,$sprite_config.height}};
    sf::Vector2f scale{$sprite_config.scale, $sprite_config.scale};
    sf::Vector2f pos{$boss_pos.x, $boss_pos.y};

    $animation.step(scale, pos, frame_rect);
    $boss_image.sprite->setScale(scale);

    if($animation.stationary) $boss_image.sprite->setPosition(pos);

    if(!sound::playing($sounds.attack) && $animation.current == 1) {
      sound::play($sounds.attack);
    }

    $boss_image.sprite->setTextureRect(frame_rect);
    window.draw(*$boss_image.sprite);
  }

  void BossFightUI::render(sf::RenderWindow& window) {
    window.draw(*$boss_background.sprite);

    if($boss_hit) {
      bounce_boss(window);
    } else {
      window.draw(*$boss_image.sprite);
    }

    if($boss_has_stage) {
      window.draw(*$boss_stage.sprite);
    }

    if($combat.hp == 0) {
      $overlay.show_text("overlay_1", L"YOU WON!");
      $overlay.show_text("overlay_4", L"CLICK TO CONTINUE...");
    }

    $status.render(window);
    $overlay.render(window);
  }

  bool BossFightUI::mouse(float x, float y, bool hover) {
    if($status.mouse(x, y, hover)) {
      dbc::log("STATUS button pressed");
    }

    if($overlay.mouse(x, y, hover)) {
      $animation.play();
      sound::play("Sword_Hit_1");
      $boss_hit = !$boss_hit;
      $combat.hp--;
    }

    return false;
  }
}
