#ifndef NOTIFICATIONS_CPP
#define NOTIFICATIONS_CPP

#include <core/inc.hpp>

auto debug::NotificationSystem::render_notifications( ) -> void
{
    const float PADDING = 16.0f;
    const float CARD_PADDING = 16.0f;
    const float SHADOW_OFFSET = 2.0f;
    const float maxWidth = 350.0f;
    const int MAX_VISIBLE_STACKED = 3;

    auto* drawList = ImGui::GetBackgroundDrawList( );
    float currentTime = ImGui::GetTime( );
    ImVec2 windowSize = ImVec2( ImGui::GetIO( ).DisplaySize );

    auto stackStartX = windowSize.x - maxWidth - PADDING;
    auto stackStartY = windowSize.y - PADDING;

    ImVec2 mousePos = ImGui::GetMousePos( );
    isHovered = ( mousePos.x >= stackStartX &&
        mousePos.x <= stackStartX + maxWidth &&
        mousePos.y >= stackStartY - NOTIFICATION_HEIGHT * 3 &&
        mousePos.y <= stackStartY );

    auto visibleCount = 0;

    if ( notifications.empty( ) ) {
        return;
    }

    for ( auto i = notifications.size( ) - 1; i >= 0; i-- ) {

        if ( i < 0 || i >= notifications.size( ) ) {
            break;
        }

        auto& notif = notifications [ i ];

        if ( !notif.isActive || visibleCount >= MAX_VISIBLE_STACKED ) continue;

        auto elapsed = currentTime - notif.showTime;
        if ( elapsed > notif.duration ) {
            notif.isActive = false;
            continue;
        }

        auto targetOffset = isHovered ?
            visibleCount * ( NOTIFICATION_HEIGHT + ImGui::CalcTextSize( notif.message.c_str( ) ).y + EXPANDED_SPACING ) :
            visibleCount * STACK_OFFSET;

        notif.currentOffset += ( targetOffset - notif.currentOffset ) / ANIMATION_SPEED;

        ImVec2 pos(
            stackStartX,
            stackStartY - NOTIFICATION_HEIGHT - ImGui::CalcTextSize( notif.message.c_str( ) ).y - notif.currentOffset
        );

        auto alpha = 1.0f;
        if ( elapsed > notif.duration - FADE_TIME ) {
            alpha = 1.0f - ( elapsed - ( notif.duration - FADE_TIME ) ) / FADE_TIME;
        }

        drawList->AddRectFilled(
            ImVec2( pos.x + SHADOW_OFFSET, pos.y + SHADOW_OFFSET ),
            ImVec2( pos.x + maxWidth + SHADOW_OFFSET, pos.y + NOTIFICATION_HEIGHT + ImGui::CalcTextSize( notif.message.c_str( ) ).y + SHADOW_OFFSET ),
            GetShadowColor( alpha ),
            0.0f
        );

        drawList->AddRectFilled(
            pos,
            ImVec2( pos.x + maxWidth, pos.y + NOTIFICATION_HEIGHT + ImGui::CalcTextSize( notif.message.c_str( ) ).y ),
            GetBackgroundColor( alpha ),
            0.0f
        );

        ImGui::PushFont( g_framework->icons_font );

        drawList->AddText(
            ImVec2( pos.x + CARD_PADDING, pos.y + CARD_PADDING ),
            ImColor { notif.icon_col.Value.x, notif.icon_col.Value.y, notif.icon_col.Value.z, notif.icon_col.Value.w * alpha },
            reinterpret_cast< const char* >( notif.icon )
        );

        ImGui::PopFont( );

        drawList->AddText(
            ImVec2( pos.x + CARD_PADDING + 20, pos.y + CARD_PADDING ),
            GetTitleColor( alpha ),
            notif.title.c_str( )
        );

        auto messageY = pos.y + CARD_PADDING * 3 + GImGui->FontSize;

        drawList->AddLine(
            ImVec2( pos.x, pos.y + CARD_PADDING * 2 + GImGui->FontSize ),
            ImVec2( pos.x + maxWidth, pos.y + CARD_PADDING * 2 + GImGui->FontSize ),
            ImGui::GetColorU32( ImGuiCol_Border )
        );

        drawList->AddText(
            ImVec2( pos.x + CARD_PADDING, messageY ),
            GetTitleColor( alpha ),
            notif.message.c_str( )
        );

        visibleCount++;
    }

    CleanupExpiredNotifications( );
}

#endif // !NOTIFICATIONS_CPP