#include "gui/storyboard.hpp"
#include "game/components.hpp"
#include "game/sound.hpp"
#include "game/config.hpp"
#include <chrono>
#include <iostream>
#include <locale>
#include <sstream>

namespace storyboard {
  UI::UI(const std::string& story_name) :
    $view_texture({SCREEN_WIDTH, SCREEN_HEIGHT}),
    $view_sprite($view_texture.getTexture())
  {
    $view_sprite.setPosition({0, 0});
    auto config = settings::get("stories");
    $story = components::convert<components::Storyboard>(config[story_name]);
    $audio = sound::get_sound_pair($story.audio).sound;
    $camera.from_story($story);
  }

  void UI::init() {
    $ui.position(0,0, SCREEN_WIDTH, SCREEN_HEIGHT);

    $ui.set<guecs::Background>($ui.MAIN, {$ui.$parser, guecs::THEME.TRANSPARENT});

    auto& background = $ui.get<guecs::Background>($ui.MAIN);
    background.set_sprite($story.image, true);

    for(auto& line : $story.layout) {
      $layout.append(line);
    }

    $ui.layout($layout);
    $audio->play();
  }

  void UI::render(sf::RenderWindow &window) {
    track_audio();
    $view_texture.clear();

    $camera.render($view_texture);
    $ui.render($view_texture);
    // $ui.debug_layout($view_texture);

    $view_texture.display();
    window.draw($view_sprite);
  }

  void UI::stop() {
    $audio->stop();
  }

  bool UI::playing() {
    return $audio->getStatus() == sf::SoundSource::Status::Playing;
  }

  sf::Time parse_time_code(const std::string& time) {
    std::chrono::seconds out{};

    std::istringstream is{time};
    is >> std::chrono::parse("%M:%S", out);
    dbc::check(!is.fail(), $F("Time parse failed: {}", time));

    return sf::Time(out);
  }

  void UI::update() {
    $camera.update();
  }

  void UI::track_audio() {
    auto& [timecode, cell_name, form, _] = $story.beats[cur_beat % $story.beats.size()];
    auto track_head = $audio->getPlayingOffset();

    auto next_beat = parse_time_code(timecode);

    if(track_head >= next_beat) {
      if($moving) return;
      $moving = true; // prevent motion until next tick

      // get the original zoom target as from
      auto& from_cell = $ui.cell_for($zoom_target);
      $camera.position(from_cell.mid_x, from_cell.mid_y);

      $zoom_target = cell_name;
      $camera.style(timecode);

      // get the new target from the cell names
      zoom($zoom_target);
      $camera.play();
      cur_beat++;
    } else {
      $moving = false;
    }
  }

  bool UI::mouse(float, float, guecs::Modifiers) {
    $audio->stop();
    return true;
  }

  void UI::zoom(const std::string &cell_name) {
    auto& cell = $ui.cell_for(cell_name);

    $camera.resize(float(cell.w));
    $camera.move(float(cell.mid_x), float(cell.mid_y));
  }

  void UI::reset() {
    $camera.reset($view_texture);
  }
}
