// Copyright (c) 2022 Dominic Masters
// 
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT

#pragma once
#include "ui/UISprite.hpp"
#include "ui/UIBorder.hpp"
#include "ui/UILabel.hpp"
#include "ui/UIEmpty.hpp"
#include "util/mathutils.hpp"
#include "visualnovel/components/VisualNovelCharacter.hpp"

#define VISUAL_NOVEL_TEXTBOX_SPEED 25.0f
#define VISUAL_NOVEL_TEXTBOX_SPEED_FASTER 40.0f

namespace Dawn {
  class VisualNovelManager;

  class VisualNovelTextbox : public UIComponent {
    private:
      int32_t lineCurrent = 0;
      glm::vec2 labelPadding = glm::vec2(0, 0);
      UIEmpty selfParent;
      float_t timeCharacter = 0.0f;
      bool_t visible = false;
      VisualNovelCharacter *character = nullptr;
      AudioAsset *talkSound = nullptr;

      void updatePositions() override;
      
      std::vector<struct ShaderPassItem> getSelfPassItems(
        glm::mat4 projection,
        glm::mat4 view,
        glm::mat4 transform
      ) override;

      /**
       * Listens for scene updates.
       */
      void textboxOnSceneUpdate();

      /**
       * Returns the count of visible lines within the textbox. Mostly used for
       * when we need to decide how to wrap.
       * 
       * @return The count of visible lines.
       */
      int32_t getCountOfVisibleLines();

    public:
      UIBorder border;
      UILabel label;

      Event<> eventCharacterRevealed;
      Event<> eventCurrentCharactersRevealed;
      Event<> eventNewPage;
      Event<> eventAllCharactersRevealed;
      Event<> eventHidden;
      Event<> eventVisible;

      /**
       * Constructs a VN Textbox.
       * 
       * @param canvas Canvas that this textbox belongs to.
       */
      VisualNovelTextbox(UICanvas *canvas);

      void show();
      void hide();
      bool_t isVisible();

      /**
       * Returns the visual novel manager (if applicable).
       * 
       * @return Visual Novel Manager instance.
       */
      VisualNovelManager * getVisualNovelManager();

      /**
       * Sets the font for this vn textbox. Passed to the underlying label.
       * 
       * @param font Font to set for this textbox.
       */
      void setFont(Font *font);

      /**
       * Sets the string (label) for this textbox.
       * 
       * @param text Localized string key to set.
       * @param fontSize Font size of the string.
       */
      void setText(std::string key, float_t fontSize);

      /**
       * Sets the string (label) for this textbox.
       * 
       * @param text Localized string key to set.
       */
      void setText(std::string key);

      /**
       * Sets the VN Character for this text.
       * 
       * @param character Character to set.
       */
      void setCharacter(VisualNovelCharacter *character);

      /**
       * Set the sound to use whenever the text is scrolling to represent a
       * character talking.
       * 
       * @param sound Sound asset to use.
       */
      void setTalkingSound(AudioAsset *sound);

      /**
       * Sets the font size to use.
       * 
       * @param fontSize Font size to use.
       */
      void setFontSize(float_t fontSize);

      /**
       * Returns the current font size.
       * 
       * @return Font size.
       */
      float_t getFontSize();

      /**
       * Sets the padding of the label. This will increase the spacing between
       * the text and the border.
       * 
       * @param padding Padding to set.
       */
      void setLabelPadding(glm::vec2 padding);

      /**
       * Returns the current label padding.
       * 
       * @return The current label padding.
       */
      glm::vec2 getLabelPadding();

      /**
       * Returns true if all of the characters that can be made visible for the
       * current textbox size have finished revealing, or false if not.
       * 
       * @return True if above statement is met.
       */
      bool_t hasRevealedAllCurrentCharacters();

      /**
       * Returns true only when every character passed previously in setText
       * has been revealed by scrolling.
       * 
       * @return True if above statement is true.
       */
      bool_t hasRevealedAllCharacters();

      /**
       * Cleans the VN Textbox.
       */
      ~VisualNovelTextbox();
  };
}