#include "Button.h"

#include "TextNode.h"
#include "GeometryNode.h"
#include "TransformNode.h"
#include "IconNode.h"

#include "FontTokens.h"
#include "ThemeManager.h"
#include "MediaResourceManager.h"

#include "PaintEvent.h"
#include "MouseEvent.h"

#include "FileLogger.h"

Button::Button(ButtonData::Component component)
    : Widget(),
      mLabel(),
      mClickFunc()
{
    mStyle.mComponent = component;
    mName = "Button";
    setWidth(150);
    setMaxWidth(150);

    setHeight(mStyle.getContainerHeight());
    setMaxHeight(mStyle.getContainerHeight());
    setRadius(mStyle.getContainerCornerRadius());
}

Button::~Button()
{

}

std::unique_ptr<Button> Button::Create(ButtonData::Component component)
{
    return std::make_unique<Button>(component);
}

void Button::setOnClickFunction(clickFunc func)
{
    mClickFunc = func;
}

void Button::setLabel(const std::string& text)
{
    if (text != mLabel)
    {
        mLabel = text;
        mContentDirty = true;
    }
}

void Button::setSvgIcon(Resource::Icon::Svg icon)
{
    if (icon != mIcon)
    {
        mIcon = icon;
        mContentDirty = true;
    }
}

void Button::setState(ButtonData::State state)
{
    if (mStyle.mState != state)
    {
        mStyle.mState = state;
        mStateDirty = true;
    }
}

void Button::setEnabled(bool isEnabled)
{
    if (mEnabled != isEnabled)
    {
        mEnabled = isEnabled;
        if (isEnabled && mStyle.mState == ButtonData::State::Disabled)
        {
            setState(ButtonData::State::Enabled);
        }
        else if (!isEnabled && mStyle.mState == ButtonData::State::Enabled)
        {
            setState(ButtonData::State::Disabled);
        }
    }
}

void Button::updateState()
{
    setBackground(mStyle.getContainerColor());
    setBackgroundOpacity(mStyle.getStateLayerOverlayOpacity());
    setBackgroundTone(mStyle.getContainerSurfaceTintColor());
    setElevation(mStyle.getContainerElevation());

    setLabelTextColor(mStyle.getLabelTextColor());
    setLabelTextOpacity(mStyle.getLabelOpacity());
    setLabelTextTypescale(mStyle.getLabelTypescale());

    setIconColor(mStyle.getIconColor());
    //setIconOpacity()
}

void Button::setLabelTextColor(Theme::Sys::Color color)
{
    if (mLabelTextColor != color)
    {
        mLabelTextColor = color;
        mMaterialDirty = true;
    }
}

void Button::setLabelTextOpacity(float opacity)
{
    if (mLabelOpacity != opacity)
    {
        mLabelOpacity = opacity;
        mMaterialDirty = true;
    }
}

void Button::setLabelTextTypescale(Theme::Sys::Typescale typescale)
{
    if (mLabelTextTypescale != typescale)
    {
        mLabelTextTypescale = typescale;
        mMaterialDirty = true;
    }
}

void Button::setIconColor(Theme::Sys::Color color)
{
    if (mIconColor != color)
    {
        mIconColor = color;
        mMaterialDirty = true;
    }
}

void Button::setIconOpacity(float opacity)
{
    if (mIconOpacity!= opacity)
    {
        mIconOpacity = opacity;
        mMaterialDirty = true;
    }
}

void Button::onMyMouseEvent(const MouseEvent* event)
{
    if (!mEnabled)
    {
        return;
    }

    if (event->getAction() == MouseEvent::Action::Pressed)
    {
        setState(ButtonData::State::Pressed);
    }
    else if (event->getAction() == MouseEvent::Action::Released)
    {
        resetState();
        if (mClickFunc)
        {
            mClickFunc(this);
        }
    }
    else if (event->getAction() == MouseEvent::Action::Enter)
    {
        resetState();
    }
    else if (event->getAction() == MouseEvent::Action::Leave)
    {
        resetState();
    }
}

void Button::resetState()
{
    if (mHasFocus)
    {
        setState(ButtonData::State::Focused);
    }
    else if (mContainsMouse)
    {
        setState(ButtonData::State::Hovered);
    }
    else if (mEnabled)
    {
        setState(ButtonData::State::Enabled);
    }
    else
    {
        setState(ButtonData::State::Disabled);
    }
}

bool Button::isDirty() const
{
    return Widget::isDirty() || mContentDirty;
}

void Button::doPaint(const PaintEvent* event)
{
    if (mTransformDirty)
    {
        mRootNode->setTransform(Transform(mLocation));
        mTransformDirty = false;
    }

    updateBackground(event);
    updateLabel(event);
    updateIcon(event);

    mContentDirty = false;
}

void Button::updateLabel(const PaintEvent* event)
{
    if (!mTextNode)
    {
        mTextNode = TextNode::Create(mLabel, Transform());
        mTextNode->setName(mName + "_TextNode");
        mTextNode->setContent(mLabel);
        mTextNode->setWidth(mSize.mWidth);
        mTextNode->setHeight(mSize.mHeight);
        mRootNode->addChild(mTextNode.get());
    }

    if (mMaterialDirty)
    {
        auto fill_color = event->getThemesManager()->getColor(mLabelTextColor);
        fill_color.setAlpha(mLabelOpacity);
        mTextNode->setFillColor(fill_color);
        
        auto size = FontTokens::getSize(mLabelTextTypescale);
        auto family = FontTokens::getFont(FontTokens::getFont(mLabelTextTypescale));
        auto font_data = FontItem(family, static_cast<float>(size));
        mTextNode->setFont(font_data);
    }

    if (mContentDirty)
    {
        mTextNode->setContent(mLabel);
    }

    if (mVisibilityDirty)
    {
        mTextNode->setIsVisible(mVisible);
    }
}

void Button::updateIcon(const PaintEvent* event)
{
    if (!mIconNode && mIcon != Resource::Icon::Svg::NONE)
    {
        mIconNode = std::make_unique<IconNode>(Transform(Point(15.0, 8.0), 0.5, 0.5));
        mIconNode->setName(mName + "_IconNode");
        mIconNode->setSvgContent(MediaResourceManager::getSvgIconNode(mIcon));
        mRootNode->addChild(mIconNode.get());
    }
    else if (mContentDirty && mIcon != Resource::Icon::Svg::NONE)
    {
        mIconNode->setSvgContent(MediaResourceManager::getSvgIconNode(mIcon));
    }

    if (!mIconNode)
    {
        return;
    }

    if (mMaterialDirty)
    {
        auto icon_fill = event->getThemesManager()->getColor(mIconColor);
        icon_fill.setAlpha(mIconOpacity);
        mIconNode->setFillColor(icon_fill);
    }

    if (mVisibilityDirty)
    {
        mIconNode->setIsVisible(mVisible);
    }
}
