#ifndef TEXT_FIELD_HPP_
#define TEXT_FIELD_HPP_

#include <Utilities/Animating.hpp>
#include <Utilities/StandardLerping.hpp>
#include <functional>
#include <optional>

#include <Widget/Widget.hpp>

/**
 * @brief A widget which allows the user to enter text.
 */
class TextField : public Widget
{
public:
    using ChangedCallback = std::function<void()>;

private:
    struct ShiftDragStatus
    {
        size_t anchor;
        size_t cursor;
    };

    static constexpr Uint32 cursorBlinkPeriod = 500;

    std::optional<size_t> selectAnchor;
    std::optional<ShiftDragStatus> shiftDragStatus;
    std::string placeholder;
    StandardLerping<glm::vec4> borderLerp;
    Uint32 blinkStartTime = 0;
    ChangedCallback onChanged = [](){};

    void insert(std::string insertion);
    void backspace();
    size_t getPosByX(int x);
    void updateFromShiftDrag(const ShiftDragStatus &status);
    std::string getSelectedText();
    
protected:
    size_t selectStart;
    size_t selectEnd;
    std::string &text;
    std::function<void()> onAccept;
    bool masked;
    int minWidth = 70;
    bool autoSelect = false;
    bool mouseMovedSinceClick = false;
    
public:
    /**
     * @brief Construct text field.
     * 
     * @param text A reference to a string, where the text shall be stored.
     * @param onAccept A function to called when the user presses ENTER (does nothing by default).
     */
    TextField(std::string &text, std::function<void()> onAccept = [](){}, bool masked = false);

    TextField(std::string &&) = delete;

    /**
     * @brief Set the placeholder text and return the text field itself.
     */
    TextField* withPlaceholder(std::string placeholder);

    /**
     * @brief Set the callback to call when the text changed, and reutrn the text field itself.
     */
    TextField* withChangedCallback(const ChangedCallback &callback);

    /**
     * @brief Sets the minimum width, and returns the text field itself.
     */
    TextField* withMinWidth(int width);

    /**
     * @brief Tell the text field to auto-select when clicked, returns the text field itself.
     */
    TextField* withAutoSelect();

    /**
     * @brief Select all text.
     */
    void selectAll();

    virtual void draw(GraphicsContext &context) override;
    virtual glm::ivec2 getMinSize() override;
    virtual void onKeyDown(SDL_Keycode keycode) override;
    virtual void onKeyUp(SDL_Keycode keycode) override;
    virtual bool isTextInput() override;
    virtual void onTextInput(std::string text) override;
    virtual void onMouseDown(Uint8 button) override;
    virtual void onMouseUp(Uint8 button) override;
    virtual void onMouseMoved(glm::ivec2 pos) override;
    virtual void getInternalTabOrder(std::vector<Widget*> &tabOrder) override;
};

#endif
