#include <catch2/catch_test_macros.hpp>
#include "graphics/textures.hpp"
#include "algos/dinkyecs.hpp"
#include "game/config.hpp"
#include <iostream>
#include <memory>
#include <chrono>
#include <thread>
#include "algos/rand.hpp"
#include "graphics/animation.hpp"
#include "game/sound.hpp"
#include "game/components.hpp"

using namespace components;
using namespace textures;
using namespace std::chrono_literals;
using namespace animation;

Animation load_animation(const string& name) {
  auto anim = animation::load("assets/animation.json", "rat_king_boss");
  anim.set_form("attack");

  anim.transform.looped = false;

  for(size_t i = 0; i < anim.sequence.durations.size(); i++) {
    anim.sequence.durations[i] = Random::uniform(1, 5);
  }

  return anim;
}

void FAKE_RENDER() {
  std::this_thread::sleep_for(Random::milliseconds(5, 32));
}

void PLAY_TEST(Animation &anim) {
  REQUIRE(anim.transform.looped == false);
  anim.play();

  while(anim.playing) {
    anim.update();
    FAKE_RENDER();
  }

  REQUIRE(anim.playing == false);
}

// /*
//  * Animation is a Sheet + Sequence + Transform.
//  *
//  * A Sheet is just a grid of images with a predefined size for each cell. Arbitrary sized cells not supported.
//  *
//  * A Sequence is a list of Sheet cells _in any order_.  See https://github.com/yottahmd/ganim8-lib. Sequences have a timing element for the cells, possibly a list of durations or a single duration.
//  *
//  * A Transform is combinations of scale and/or position easing/motion, shader effects, and things like if it's looped or toggled.
//  *
//  * I like the ganim8 onLoop concept, just a callback that says what to do when the animation has looped.
//  */
// TEST_CASE("new animation system", "[animation-new]") {
//   textures::init();
//   sound::init();
//   sound::mute(true);
//
//   auto anim = load_animation("rat_king_boss");
//   PLAY_TEST(anim);
//
//   // test that toggled works
//   anim.transform.toggled = true;
//   PLAY_TEST(anim);
//   REQUIRE(anim.sequence.current == anim.sequence.frames.size() - 1);
//   anim.transform.toggled = false;
//
//   bool onLoop_ran = false;
//   anim.onLoop = [&](auto& seq, auto& tr) -> bool {
//     seq.current = 0;
//     onLoop_ran = true;
//     return tr.looped;
//   };
//
//   PLAY_TEST(anim);
//   REQUIRE(onLoop_ran == true);
//
//   // only runs twice
//   anim.onLoop = [](auto& seq, auto& tr) -> bool {
//     if(seq.loop_count == 2) {
//       seq.current = 0;
//       return false;
//     } else {
//       seq.current = seq.current % seq.frame_count;
//       return true;
//     }
//   };
//
//   PLAY_TEST(anim);
//   REQUIRE(anim.sequence.loop_count == 2);
// }
//
//
// TEST_CASE("confirm frame sequencing works", "[animation-new]") {
//   textures::init();
//   sound::init();
//   sound::mute(true);
//
//   auto anim = load_animation("rat_king_boss");
//
//   auto boss = textures::get_sprite("rat_king_boss");
//   sf::IntRect init_rect{{0,0}, {anim.sheet.frame_width, anim.sheet.frame_height}};
//
//   anim.play();
//   bool loop_ran = false;
//
//   // this will check that it moved to the next frame
//   anim.onLoop = [&](auto& seq, auto& tr) -> bool {
//     seq.current = 0;
//     loop_ran = true;
//     return false;
//   };
//
//   anim.onFrame = [&](){
//     anim.apply(*boss.sprite);
//   };
//
//   while(anim.playing) {
//     anim.update();
//     FAKE_RENDER();
//   }
//
//   REQUIRE(loop_ran == true);
//   REQUIRE(anim.playing == false);
// }
//
// TEST_CASE("confirm transition changes work", "[animation-new]") {
//   textures::init();
//   sound::init();
//   sound::mute(true);
//
//   auto sprite = *textures::get_sprite("rat_king_boss").sprite;
//   sf::Vector2f pos{100,100};
//   sprite.setPosition(pos);
//   auto scale = sprite.getScale();
//   auto anim = load_animation("rat_king_boss");
//
//   // also testing that onFrame being null means it's not run
//   REQUIRE(anim.onFrame == nullptr);
//
//   anim.play();
//   REQUIRE(anim.playing == true);
//
//   while(anim.playing) {
//     anim.update();
//     anim.motion(sprite, pos, scale);
//     FAKE_RENDER();
//   }
//
//   REQUIRE(anim.playing == false);
//   REQUIRE(pos == sf::Vector2f{100, 100});
//   REQUIRE(scale != sf::Vector2f{0,0});
// }

TEST_CASE("playing with delta time", "[animation-new]") {
  animation::Timer timer;
  timer.start();

  for(int i = 0; i < 20; i++) {
    FAKE_RENDER();
    auto [tick_count, alpha] = timer.commit();
    // fmt::println("tick: {}, alpha: {}", tick_count, alpha);
  }
}
