/*
 * Copyright (c) 2010-2026 OTClient <https://github.com/edubart/otclient>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "uiitem.h"

#include "framework/graphics/drawpoolmanager.h"
#include "framework/otml/otmlnode.h"
#include "gameconfig.h"
#include "item.h"

UIItem::UIItem() { setProp(PropDraggable, true, false); }

void UIItem::drawSelf(const DrawPoolType drawPane)
{
    if (drawPane != DrawPoolType::FOREGROUND)
        return;

    // draw style components in order
    if (m_backgroundColor.aF() > Fw::MIN_ALPHA) {
        Rect backgroundDestRect = m_rect;
        backgroundDestRect.expand(-m_borderWidth.top, -m_borderWidth.right, -m_borderWidth.bottom, -m_borderWidth.left);
        drawBackground(m_rect);
    }

    drawImage(m_rect);

    if (m_itemVisible && m_item) {
        if (m_item->getClientId() != m_itemId) {
            m_item->setId(m_itemId);
        }

        const int exactSize = std::max<int>(g_gameConfig.getSpriteSize(), m_item->getExactSize());

        g_drawPool.bindFrameBuffer(exactSize);
        m_item->setColor(m_color);
        m_item->draw(Point(exactSize - g_gameConfig.getSpriteSize()) + m_item->getDisplacement());
        g_drawPool.releaseFrameBuffer(getPaddingRect(), m_flipDirection);

        const auto itemCountFont = g_gameConfig.getItemCountFont();
        const auto& countFont = itemCountFont ? itemCountFont : m_font;

        const int displayCount = m_displayCount > 0 ? m_displayCount
                               : (m_item->isStackable() ? m_item->getCount() : 0);
        const bool shouldDrawCount = m_displayCount > 0 ? (displayCount >= 1) : (displayCount > 1);
        if (countFont && m_alwaysShowCount && shouldDrawCount) {
            static constexpr Color STACK_COLOR(191, 191, 191);
            std::string countText;
            if (displayCount < 1000) {
                countText = std::to_string(displayCount);
            } else if (displayCount < 10000) {
                countText = fmt::format("{},{:03d}", displayCount / 1000, displayCount % 1000);
            } else {
                countText = fmt::format("{}K", displayCount / 1000);
            }
            countFont->drawText(countText, Rect(m_rect.topLeft(), m_rect.bottomRight()), STACK_COLOR, Fw::AlignBottomRight);
        }

        if (countFont && m_showDuration) {
            const auto secs = m_item->getDurationTime();
            if (secs > 0) {
                std::string durationText;
                if (secs >= 3600) {
                    durationText = fmt::format("{}h{:02}m", secs / 3600, (secs % 3600) / 60);
                } else if (secs >= 60) {
                    durationText = fmt::format("{}m{:02}", secs / 60, secs % 60);
                } else {
                    durationText = fmt::format("{}s", secs);
                }
                countFont->drawText(durationText, Rect(m_rect.topLeft(), m_rect.bottomRight()), Color::white, Fw::AlignBottomLeft);
            }
        }

        if (countFont && m_showCharges && m_item->getCharges() > 0) {
            countFont->drawText(std::to_string(m_item->getCharges()), Rect(m_rect.x() + 2, m_rect.y() + 2, m_rect.width(), m_rect.height()), Color::white, Fw::AlignTopLeft);
        }

#ifdef FRAMEWORK_EDITOR
        if (m_showId)
            m_font->drawText(std::to_string(m_item->getServerId()), m_rect, Fw::AlignBottomRight);
#endif
    }

    drawBorder(m_rect);
    drawIcon(m_rect);
    drawText(m_rect);
}

void UIItem::setItemId(const int id)
{
    m_itemId = id;
    m_displayCount = 0;

    if (id == 0)
        m_item = nullptr;
    else if (m_item)
        m_item->setId(id);
    else
        m_item = Item::create(id);

    if (m_item)
        m_item->setShader(m_shaderName);

    callLuaField("onItemChange");
}

void UIItem::setItemCount(const int count)
{
    if (m_item) m_item->setCount(count);

    callLuaField("onItemChange");
}

void UIItem::setItemSubType(const int subType)
{
    if (m_item) m_item->setSubType(subType);

    callLuaField("onItemChange");
}

void UIItem::setItem(const ItemPtr& item)
{
    m_item = item;
    m_displayCount = 0;
    if (item)
        m_itemId = item->getClientId();

    callLuaField("onItemChange");
}

void UIItem::onStyleApply(const std::string_view styleName, const OTMLNodePtr& styleNode)
{
    for (const auto& node : styleNode->children()) {
        if (node->tag() == "item-id")
            setItemId(node->value<int>());
        else if (node->tag() == "item-count")
            setItemCount(node->value<int>());
        else if (node->tag() == "item-visible")
            setItemVisible(node->value<bool>());
        else if (node->tag() == "virtual")
            setVirtual(node->value<bool>());
        else if (node->tag() == "show-id")
            m_showId = node->value<bool>();
        else if (node->tag() == "always-show-count")
            m_alwaysShowCount = node->value<bool>();
        else if (node->tag() == "flip-direction")
            setFlipDirection(node->value<uint8_t>());
    }

    UIWidget::onStyleApply(styleName, styleNode);
}

int UIItem::getItemId() { return m_item ? m_item->getId() : 0; }
int UIItem::getItemCount() { return m_item ? m_item->getCount() : 0; }
int UIItem::getItemSubType() { return m_item ? m_item->getSubType() : 0; }
int UIItem::getItemCountOrSubType() { return m_item ? m_item->getCountOrSubType() : 0; }

void UIItem::setShader(std::string_view name) {
    m_shaderName = name;
    if (getItem()) getItem()->setShader(name);
}

bool UIItem::hasShader() { return getItem() ? getItem()->getShader() != nullptr : false; }
