using Dalamud.Interface;
using Dalamud.Interface.Utility;
using Dalamud.Interface.Utility.Raii;
using LightlessSync.LightlessConfiguration;
using LightlessSync.LightlessConfiguration.Models;
using LightlessSync.Services;
using LightlessSync.Services.Mediator;
using LightlessSync.UI.Models;
using LightlessSync.UI.Style;
using Microsoft.Extensions.Logging;

using System.Numerics;
using Dalamud.Bindings.ImGui;

namespace LightlessSync.UI;

public class LightlessNotificationUi : WindowMediatorSubscriberBase
{
    private const float _notificationMinHeight = 60f;
    private const float _notificationMaxHeight = 250f;
    private const float _windowPaddingOffset = 6f;
    private const float _slideAnimationDistance = 100f;
    private const float _outAnimationSpeedMultiplier = 0.7f;
    private const float _contentPaddingX = 10f;
    private const float _contentPaddingY = 6f;
    private const float _titleMessageSpacing = 4f;
    private const float _actionButtonSpacing = 8f;
    
    private readonly List<LightlessNotification> _notifications = [];
    private readonly object _notificationLock = new();
    private readonly LightlessConfigService _configService;
    private readonly Dictionary<string, float> _notificationYOffsets = [];
    private readonly Dictionary<string, float> _notificationTargetYOffsets = [];
    private readonly Dictionary<string, Vector4> _notificationBackgrounds = [];

    public LightlessNotificationUi(ILogger<LightlessNotificationUi> logger, LightlessMediator mediator, PerformanceCollectorService performanceCollector, LightlessConfigService configService) 
        : base(logger, mediator, "Lightless Notifications##LightlessNotifications", performanceCollector)
    {
        _configService = configService;
        Flags = ImGuiWindowFlags.NoDecoration |
                ImGuiWindowFlags.NoMove | 
                ImGuiWindowFlags.NoResize | 
                ImGuiWindowFlags.NoSavedSettings |
                ImGuiWindowFlags.NoFocusOnAppearing |
                ImGuiWindowFlags.NoNav |
                ImGuiWindowFlags.NoBackground |
                ImGuiWindowFlags.NoCollapse |
                ImGuiWindowFlags.NoTitleBar |
                ImGuiWindowFlags.NoScrollbar |
                ImGuiWindowFlags.AlwaysAutoResize;  
                
        PositionCondition = ImGuiCond.Always;
        SizeCondition = ImGuiCond.FirstUseEver;
        IsOpen = false;
        RespectCloseHotkey = false;
        DisableWindowSounds = true;
        
        Mediator.Subscribe<LightlessNotificationMessage>(this, HandleNotificationMessage);
        Mediator.Subscribe<LightlessNotificationDismissMessage>(this, HandleNotificationDismissMessage);
        Mediator.Subscribe<ClearAllNotificationsMessage>(this, HandleClearAllNotifications);
    }
    private void HandleNotificationMessage(LightlessNotificationMessage message) => AddNotification(message.Notification);
    private void HandleNotificationDismissMessage(LightlessNotificationDismissMessage message) => RemoveNotification(message.NotificationId);
    private void HandleClearAllNotifications(ClearAllNotificationsMessage message) => ClearAllNotifications();

    public void AddNotification(LightlessNotification notification)
    {
        lock (_notificationLock)
        {
            var existingNotification = _notifications.FirstOrDefault(n => string.Equals(n.Id, notification.Id, StringComparison.Ordinal));
            if (existingNotification != null)
            {
                UpdateExistingNotification(existingNotification, notification);
            }
            else
            {
                _notifications.Add(notification);
                _logger.LogTrace("Added new notification: {Title}", notification.Title);
            }
            
            if (!IsOpen) IsOpen = true;
        }
    }
    
    private void UpdateExistingNotification(LightlessNotification existing, LightlessNotification updated)
    {
        existing.Message = updated.Message;
        existing.Progress = updated.Progress;
        existing.ShowProgress = updated.ShowProgress;
        existing.Title = updated.Title;
        
        // Reset the duration timer on every update for download notifications
        if (updated.Type == NotificationType.Download)
        {
            existing.CreatedAt = DateTime.UtcNow;
        }
        
        _logger.LogTrace("Updated existing notification: {Title}", updated.Title);
    }

    public void RemoveNotification(string id)
    {
        lock (_notificationLock)
        {
            var notification = _notifications.FirstOrDefault(n => string.Equals(n.Id, id, StringComparison.Ordinal));
            if (notification != null)
            {
                StartOutAnimation(notification);
            }
        }
    }
    
    public void ClearAllNotifications()
    {
        lock (_notificationLock)
        {
            foreach (var notification in _notifications)
            {
                StartOutAnimation(notification);
            }
        }
    }
    
    private static void StartOutAnimation(LightlessNotification notification)
    {
        notification.IsAnimatingOut = true;
        notification.IsAnimatingIn = false;
    }
    
    private static bool ShouldRemoveNotification(LightlessNotification notification) =>
        notification.IsAnimatingOut && notification.AnimationProgress <= 0.01f;

    protected override void DrawInternal()
    {
        ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.Zero);

        lock (_notificationLock)
        {
            UpdateNotifications();

            if (_notifications.Count == 0)
            {
                ImGui.PopStyleVar();
                IsOpen = false;
                return;
            }

            var viewport = ImGui.GetMainViewport();
            
            // Window auto-resizes based on content (AlwaysAutoResize flag)
            Position = CalculateWindowPosition(viewport);
            PositionCondition = ImGuiCond.Always;
            
            DrawAllNotifications();
        }

        ImGui.PopStyleVar();
    }
    
    private Vector2 CalculateWindowPosition(ImGuiViewportPtr viewport)
    {
        var corner = _configService.Current.NotificationCorner;
        var offsetX = _configService.Current.NotificationOffsetX;
        var offsetY = _configService.Current.NotificationOffsetY;
        var width = _configService.Current.NotificationWidth;

        float posX = corner == NotificationCorner.Left
            ? viewport.WorkPos.X + offsetX - _windowPaddingOffset
            : viewport.WorkPos.X + viewport.WorkSize.X - width - offsetX - _windowPaddingOffset;

        float posY = viewport.WorkPos.Y + offsetY;

        return new Vector2(posX, posY);
    }
    
    private void DrawAllNotifications()
    {
        var startY = ImGui.GetCursorPosY();

        for (int i = 0; i < _notifications.Count; i++)
        {
            var notification = _notifications[i];

            if (_notificationYOffsets.TryGetValue(notification.Id, out var yOffset))
                ImGui.SetCursorPosY(startY + yOffset);

            DrawNotification(notification);
        }
    }

    private void UpdateNotifications()
    {
        var deltaTime = ImGui.GetIO().DeltaTime;
        EnforceMaxNotificationLimit();
        UpdateAnimationsAndRemoveExpired(deltaTime);
    }
    
    private void EnforceMaxNotificationLimit()
    {
        var maxNotifications = _configService.Current.MaxSimultaneousNotifications;
        while (_notifications.Count(n => !n.IsAnimatingOut) > maxNotifications)
        {
            var oldestNotification = _notifications
                .Where(n => !n.IsAnimatingOut)
                .OrderBy(n => n.CreatedAt)
                .FirstOrDefault();
            
            if (oldestNotification != null)
            {
                StartOutAnimation(oldestNotification);
            }
        }
    }
    
    private void UpdateAnimationsAndRemoveExpired(float deltaTime)
    {
        UpdateTargetYPositions();
        
        for (int i = _notifications.Count - 1; i >= 0; i--)
        {
            var notification = _notifications[i];
            UpdateNotificationAnimation(notification, deltaTime);
            UpdateNotificationYOffset(notification, deltaTime);
            
            if (ShouldRemoveNotification(notification))
            {
                _notifications.RemoveAt(i);
                _notificationYOffsets.Remove(notification.Id);
                _notificationTargetYOffsets.Remove(notification.Id);
                _notificationBackgrounds.Remove(notification.Id);
            }
        }
    }
    
    private void UpdateTargetYPositions()
    {
        float currentY = 0f;
        
        for (int i = 0; i < _notifications.Count; i++)
        {
            var notification = _notifications[i];
            
            if (!_notificationTargetYOffsets.ContainsKey(notification.Id))
            {
                _notificationTargetYOffsets[notification.Id] = currentY;
                _notificationYOffsets[notification.Id] = currentY;
            }
            else
            {
                _notificationTargetYOffsets[notification.Id] = currentY;
            }
            
            currentY += CalculateNotificationHeight(notification) + _configService.Current.NotificationSpacing;
        }
    }
    
    private void UpdateNotificationYOffset(LightlessNotification notification, float deltaTime)
    {
        if (!_notificationYOffsets.ContainsKey(notification.Id) || !_notificationTargetYOffsets.ContainsKey(notification.Id))
            return;
        
        var current = _notificationYOffsets[notification.Id];
        var target = _notificationTargetYOffsets[notification.Id];
        var diff = target - current;
        
        if (Math.Abs(diff) < 0.5f)
        {
            _notificationYOffsets[notification.Id] = target;
        }
        else
        {
            var speed = _configService.Current.NotificationSlideSpeed;
            _notificationYOffsets[notification.Id] = current + (diff * deltaTime * speed);
        }
    }
    
    private void UpdateNotificationAnimation(LightlessNotification notification, float deltaTime)
    {
        if (notification.IsAnimatingIn && notification.AnimationProgress < 1f)
        {
            notification.AnimationProgress = Math.Min(1f, 
                notification.AnimationProgress + deltaTime * _configService.Current.NotificationAnimationSpeed);
        }
        else if (notification.IsAnimatingOut && notification.AnimationProgress > 0f)
        {
            notification.AnimationProgress = Math.Max(0f, 
                notification.AnimationProgress - deltaTime * _configService.Current.NotificationAnimationSpeed * _outAnimationSpeedMultiplier);
        }
        else if (!notification.IsAnimatingOut && !notification.IsDismissed)
        {
            notification.IsAnimatingIn = false;
            
            if (notification.IsExpired)
            {
                StartOutAnimation(notification);
            }
        }
    }
    
    private Vector2 CalculateSlideOffset(float alpha)
    {
        var distance = (1f - alpha) * _slideAnimationDistance;
        var corner = _configService.Current.NotificationCorner;
        return corner == NotificationCorner.Left ? new Vector2(-distance, 0) : new Vector2(distance, 0);
    }

    private void DrawNotification(LightlessNotification notification)
    {
        var alpha = notification.AnimationProgress;
        if (alpha <= 0f) return;

        var slideOffset = CalculateSlideOffset(alpha);
        var originalCursorPos = ImGui.GetCursorPos();
        ImGui.SetCursorPos(originalCursorPos + slideOffset);

        var notificationHeight = CalculateNotificationHeight(notification);
        var notificationWidth = _configService.Current.NotificationWidth;
        
        ImGui.PushStyleVar(ImGuiStyleVar.WindowPadding, Vector2.Zero);
        
        using var child = ImRaii.Child($"notification_{notification.Id}", 
            new Vector2(notificationWidth, notificationHeight), 
            false, ImGuiWindowFlags.NoScrollbar);
            
        if (child.Success)
        {
            DrawNotificationContent(notification, alpha);
        }
        
        ImGui.PopStyleVar();
    }

    private void DrawNotificationContent(LightlessNotification notification, float alpha)
    {
        var drawList = ImGui.GetWindowDrawList();
        var windowPos = ImGui.GetWindowPos();
        var windowSize = ImGui.GetWindowSize();
        
        var accentColor = GetNotificationAccentColor(notification.Type);
        var bgColor = CalculateBackgroundColor(notification, alpha, ImGui.IsWindowHovered(), accentColor);
        var accentColorWithAlpha = accentColor;
        accentColorWithAlpha.W *= alpha;

        DrawShadow(drawList, windowPos, windowSize, alpha);
        HandleClickToDismiss(notification);
        DrawBackground(drawList, windowPos, windowSize, bgColor);
        DrawAccentBar(drawList, windowPos, windowSize, accentColorWithAlpha);
        DrawDurationProgressBar(notification, alpha, windowPos, windowSize, drawList);
        
        // Draw download progress bar above duration bar for download notifications
        if (notification.Type == NotificationType.Download && notification.ShowProgress)
        {
            DrawDownloadProgressBar(notification, alpha, windowPos, windowSize, drawList);
        }
        
        DrawNotificationText(notification, alpha);
    }
    
    private Vector4 CalculateBackgroundColor(LightlessNotification notification, float alpha, bool isHovered, Vector4 accentColor)
    {
        var baseOpacity = _configService.Current.NotificationOpacity;
        var finalOpacity = baseOpacity * alpha;
        
        float boost = Luminance.ComputeHighlight(null, accentColor);
        
        var baseBg = new Vector4(
            30f/255f + boost,
            30f/255f + boost,
            30f/255f + boost,
            finalOpacity
        );
        
        if (!_notificationBackgrounds.ContainsKey(notification.Id))
        {
            _notificationBackgrounds[notification.Id] = baseBg;
        }
        
        var currentBg = _notificationBackgrounds[notification.Id];
        var bgColor = Luminance.BackgroundContrast(null, accentColor, baseBg, ref currentBg);
        _notificationBackgrounds[notification.Id] = currentBg;
        
        bgColor.W = finalOpacity;
        if (isHovered)
        {
            bgColor = new Vector4(
                bgColor.X * 1.1f,
                bgColor.Y * 1.1f,
                bgColor.Z * 1.1f,
                Math.Min(bgColor.W, 0.98f)
            );
        }
        
        return bgColor;
    }
    
    private static void DrawShadow(ImDrawListPtr drawList, Vector2 windowPos, Vector2 windowSize, float alpha)
    {
        var shadowOffset = new Vector2(1f, 1f);
        var shadowColor = new Vector4(0f, 0f, 0f, 0.4f * alpha);
        drawList.AddRectFilled(
            windowPos + shadowOffset,
            windowPos + windowSize + shadowOffset,
            ImGui.ColorConvertFloat4ToU32(shadowColor),
            3f
        );
    }
    
    private void HandleClickToDismiss(LightlessNotification notification)
    {
        var pos = ImGui.GetWindowPos();
        var size = ImGui.GetWindowSize();
        bool hovered = ImGui.IsMouseHoveringRect(pos, new Vector2(pos.X + size.X, pos.Y + size.Y));

        if ((hovered || ImGui.IsWindowHovered()) && 
            _configService.Current.DismissNotificationOnClick && 
            notification.Actions.Count == 0 && 
            ImGui.IsMouseClicked(ImGuiMouseButton.Left))
        {
            notification.IsDismissed = true;
            StartOutAnimation(notification);
        }
    }
    
    private static void DrawBackground(ImDrawListPtr drawList, Vector2 windowPos, Vector2 windowSize, Vector4 bgColor)
    {
        drawList.AddRectFilled(
            windowPos,
            windowPos + windowSize,
            ImGui.ColorConvertFloat4ToU32(bgColor),
            3f
        );
    }
    
    private void DrawAccentBar(ImDrawListPtr drawList, Vector2 windowPos, Vector2 windowSize, Vector4 accentColor)
    {
        var accentWidth = _configService.Current.NotificationAccentBarWidth;
        if (accentWidth <= 0f) return;
        
        var corner = _configService.Current.NotificationCorner;
        Vector2 accentStart, accentEnd;
        
        if (corner == NotificationCorner.Left)
        {
            accentStart = windowPos + new Vector2(windowSize.X - accentWidth, 0);
            accentEnd = windowPos + windowSize;
        }
        else
        {
            accentStart = windowPos;
            accentEnd = windowPos + new Vector2(accentWidth, windowSize.Y);
        }
        
        drawList.AddRectFilled(
            accentStart,
            accentEnd,
            ImGui.ColorConvertFloat4ToU32(accentColor),
            3f
        );
    }

    private static void DrawDurationProgressBar(LightlessNotification notification, float alpha, Vector2 windowPos, Vector2 windowSize, ImDrawListPtr drawList)
    {
        var progress = CalculateDurationProgress(notification);
        var progressBarColor = UIColors.Get("LightlessBlue");
        var progressHeight = 2f;
        var progressY = windowPos.Y + windowSize.Y - progressHeight;
        var progressWidth = windowSize.X * progress;

        DrawProgressBackground(drawList, windowPos, windowSize, progressY, progressHeight, progressBarColor, alpha);
        
        if (progress > 0)
        {
            DrawProgressForeground(drawList, windowPos, progressY, progressHeight, progressWidth, progressBarColor, alpha);
        }
    }
    
    private static void DrawDownloadProgressBar(LightlessNotification notification, float alpha, Vector2 windowPos, Vector2 windowSize, ImDrawListPtr drawList)
    {
        var progress = Math.Clamp(notification.Progress, 0f, 1f);
        var progressBarColor = UIColors.Get("LightlessGreen");
        var progressHeight = 3f;
        // Position above the duration bar (2px duration bar + 1px spacing)
        var progressY = windowPos.Y + windowSize.Y - progressHeight - 3f;
        var progressWidth = windowSize.X * progress;

        DrawProgressBackground(drawList, windowPos, windowSize, progressY, progressHeight, progressBarColor, alpha);
        
        if (progress > 0)
        {
            DrawProgressForeground(drawList, windowPos, progressY, progressHeight, progressWidth, progressBarColor, alpha);
        }
    }
    
    private static float CalculateDurationProgress(LightlessNotification notification)
    {
        // Calculate duration timer progress
        var elapsed = DateTime.UtcNow - notification.CreatedAt;
        return Math.Min(1.0f, (float)(elapsed.TotalSeconds / notification.Duration.TotalSeconds));
    }
    
    private static void DrawProgressBackground(ImDrawListPtr drawList, Vector2 windowPos, Vector2 windowSize, float progressY, float progressHeight, Vector4 progressBarColor, float alpha)
    {
        var bgProgressColor = new Vector4(progressBarColor.X * 0.3f, progressBarColor.Y * 0.3f, progressBarColor.Z * 0.3f, 0.5f * alpha);
        drawList.AddRectFilled(
            new Vector2(windowPos.X, progressY),
            new Vector2(windowPos.X + windowSize.X, progressY + progressHeight),
            ImGui.ColorConvertFloat4ToU32(bgProgressColor),
            0f
        );
    }
    
    private static void DrawProgressForeground(ImDrawListPtr drawList, Vector2 windowPos, float progressY, float progressHeight, float progressWidth, Vector4 progressBarColor, float alpha)
    {
        var progressColor = progressBarColor;
        progressColor.W *= alpha;
        drawList.AddRectFilled(
            new Vector2(windowPos.X, progressY),
            new Vector2(windowPos.X + progressWidth, progressY + progressHeight),
            ImGui.ColorConvertFloat4ToU32(progressColor),
            0f
        );
    }

    private void DrawNotificationText(LightlessNotification notification, float alpha)
    {
        var contentPos = new Vector2(_contentPaddingX, _contentPaddingY);
        var windowSize = ImGui.GetWindowSize();
        var contentWidth = CalculateContentWidth(windowSize.X);
        
        ImGui.SetCursorPos(contentPos);
        
        var titleHeight = DrawTitle(notification, contentWidth, alpha);
        DrawMessage(notification, contentPos, contentWidth, titleHeight, alpha);
        
        if (HasActions(notification))
        {
            PositionActionsAtBottom(windowSize.Y);
            DrawNotificationActions(notification, contentWidth, alpha);
        }
    }
    
    private static float CalculateContentWidth(float windowWidth) => 
        windowWidth - (_contentPaddingX * 2);
    
    private static bool HasActions(LightlessNotification notification) => 
        notification.Actions.Count > 0;
    
    private static void PositionActionsAtBottom(float windowHeight)
    {
        var actionHeight = ImGui.GetFrameHeight();
        var bottomY = windowHeight - _contentPaddingY - actionHeight;
        ImGui.SetCursorPosY(bottomY);
        ImGui.SetCursorPosX(_contentPaddingX);
    }
    
    private float DrawTitle(LightlessNotification notification, float contentWidth, float alpha)
    {
        var titleColor = new Vector4(1f, 1f, 1f, alpha);
        var titleText = FormatTitleText(notification);
        
        using (ImRaii.PushColor(ImGuiCol.Text, titleColor))
        {
            return DrawWrappedText(titleText, contentWidth);
        }
    }
    
    private string FormatTitleText(LightlessNotification notification)
    {
        if (!_configService.Current.ShowNotificationTimestamp)
            return notification.Title;
            
        var timestamp = notification.CreatedAt.ToLocalTime().ToString("HH:mm:ss");
        return $"[{timestamp}] {notification.Title}";
    }
    
    private static float DrawWrappedText(string text, float wrapWidth)
    {
        ImGui.PushTextWrapPos(ImGui.GetCursorPosX() + wrapWidth);
        var startY = ImGui.GetCursorPosY();
        ImGui.TextWrapped(text);
        var height = ImGui.GetCursorPosY() - startY;
        ImGui.PopTextWrapPos();
        return height;
    }
    
    private static void DrawMessage(LightlessNotification notification, Vector2 contentPos, float contentWidth, float titleHeight, float alpha)
    {
        if (string.IsNullOrEmpty(notification.Message)) return;
        
        var messagePos = contentPos + new Vector2(0f, titleHeight + _titleMessageSpacing);
        var messageColor = new Vector4(0.9f, 0.9f, 0.9f, alpha);
        
        ImGui.SetCursorPos(messagePos);
        
        using (ImRaii.PushColor(ImGuiCol.Text, messageColor))
        {
            DrawWrappedText(notification.Message, contentWidth);
        }
    }

    private void DrawNotificationActions(LightlessNotification notification, float availableWidth, float alpha)
    {
        var buttonWidth = CalculateActionButtonWidth(notification.Actions.Count, availableWidth);
        
        _logger.LogTrace("Drawing {ActionCount} notification actions, buttonWidth: {ButtonWidth}, availableWidth: {AvailableWidth}", 
            notification.Actions.Count, buttonWidth, availableWidth);
        
        var startX = ImGui.GetCursorPosX();
        
        for (int i = 0; i < notification.Actions.Count; i++)
        {
            if (i > 0)
            {
                ImGui.SameLine();
                PositionActionButton(i, startX, buttonWidth);
            }
            DrawActionButton(notification.Actions[i], notification, alpha, buttonWidth);
        }
    }
    
    private static float CalculateActionButtonWidth(int actionCount, float availableWidth)
    {
        var totalSpacing = (actionCount - 1) * _actionButtonSpacing;
        return (availableWidth - totalSpacing) / actionCount;
    }
    
    private static void PositionActionButton(int index, float startX, float buttonWidth)
    {
        var xPosition = startX + index * (buttonWidth + _actionButtonSpacing);
        ImGui.SetCursorPosX(xPosition);
    }

    private void DrawActionButton(LightlessNotificationAction action, LightlessNotification notification, float alpha, float buttonWidth)
    {
        _logger.LogTrace("Drawing action button: {ActionId} - {ActionLabel}, width: {ButtonWidth}", action.Id, action.Label, buttonWidth);
        
        var buttonColor = action.Color;
        buttonColor.W *= alpha;
        
        var hoveredColor = buttonColor * 1.1f;
        hoveredColor.W = buttonColor.W;
        
        var activeColor = buttonColor * 0.9f;
        activeColor.W = buttonColor.W;
        
        using (ImRaii.PushColor(ImGuiCol.Button, buttonColor))
        using (ImRaii.PushColor(ImGuiCol.ButtonHovered, hoveredColor))
        using (ImRaii.PushColor(ImGuiCol.ButtonActive, activeColor))
        using (ImRaii.PushColor(ImGuiCol.Text, new Vector4(1f, 1f, 1f, alpha)))
        {
            var buttonPressed = false;
            
            if (action.Icon != FontAwesomeIcon.None)
            {
                buttonPressed = DrawIconTextButton(action.Icon, action.Label, buttonWidth);
            }
            else
            {
                buttonPressed = ImGui.Button(action.Label, new Vector2(buttonWidth, 0));
            }
            
            _logger.LogTrace("Button {ActionId} pressed: {ButtonPressed}", action.Id, buttonPressed);
            
            if (buttonPressed)
            {
                try
                {
                    _logger.LogTrace("Executing action: {ActionId}", action.Id);
                    action.OnClick(notification);
                    _logger.LogTrace("Action executed successfully: {ActionId}", action.Id);
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "Error executing notification action: {ActionId}", action.Id);
                }
            }
        }
    }
    
    private static bool DrawIconTextButton(FontAwesomeIcon icon, string text, float width)
    {
        var drawList = ImGui.GetWindowDrawList();
        ImGui.GetCursorScreenPos();
        var frameHeight = ImGui.GetFrameHeight();
        
        Vector2 iconSize;
        using (ImRaii.PushFont(UiBuilder.IconFont))
        {
            iconSize = ImGui.CalcTextSize(icon.ToIconString());
        }
        
        var textSize = ImGui.CalcTextSize(text);
        var spacing = 3f * ImGuiHelpers.GlobalScale;
        var totalTextWidth = iconSize.X + spacing + textSize.X;
        
        var buttonPressed = ImGui.InvisibleButton($"btn_{icon}_{text}", new Vector2(width, frameHeight));
        
        var buttonMin = ImGui.GetItemRectMin();
        var buttonMax = ImGui.GetItemRectMax();
        var buttonSize = buttonMax - buttonMin;
        
        var buttonColor = ImGui.GetColorU32(ImGuiCol.Button);
        if (ImGui.IsItemHovered())
            buttonColor = ImGui.GetColorU32(ImGuiCol.ButtonHovered);
        if (ImGui.IsItemActive())
            buttonColor = ImGui.GetColorU32(ImGuiCol.ButtonActive);
        
        drawList.AddRectFilled(buttonMin, buttonMax, buttonColor, 3f);
        
        var iconPos = buttonMin + new Vector2((buttonSize.X - totalTextWidth) / 2f, (buttonSize.Y - iconSize.Y) / 2f);
        var textPos = iconPos + new Vector2(iconSize.X + spacing, (iconSize.Y - textSize.Y) / 2f);
        
        var textColor = ImGui.GetColorU32(ImGuiCol.Text);
        
        // Draw icon
        using (ImRaii.PushFont(UiBuilder.IconFont))
        {
            drawList.AddText(iconPos, textColor, icon.ToIconString());
        }
        
        // Draw text
        drawList.AddText(textPos, textColor, text);
        
        return buttonPressed;
    }

    private float CalculateNotificationHeight(LightlessNotification notification)
    {
        var contentWidth = CalculateContentWidth(_configService.Current.NotificationWidth);
        var height = 12f;
        
        height += CalculateTitleHeight(notification, contentWidth);
        height += CalculateMessageHeight(notification, contentWidth);
        
        if (notification.ShowProgress)
        {
            height += 12f;
        }
        
        if (notification.Actions.Count > 0)
        {
            height += ImGui.GetStyle().ItemSpacing.Y;
            height += ImGui.GetFrameHeight();
            height += 12f;
        }
        
        return Math.Clamp(height, _notificationMinHeight, _notificationMaxHeight);
    }
    
    private float CalculateTitleHeight(LightlessNotification notification, float contentWidth)
    {
        var titleText = _configService.Current.ShowNotificationTimestamp
            ? $"[{notification.CreatedAt.ToLocalTime():HH:mm:ss}] {notification.Title}"
            : notification.Title;
        
        return ImGui.CalcTextSize(titleText, true, contentWidth).Y;
    }
    
    private static float CalculateMessageHeight(LightlessNotification notification, float contentWidth)
    {
        if (string.IsNullOrEmpty(notification.Message)) return 0f;
        
        var messageHeight = ImGui.CalcTextSize(notification.Message, true, contentWidth).Y;
        return 4f + messageHeight;
    }

    private static Vector4 GetNotificationAccentColor(NotificationType type)
    {
        return type switch
        {
            NotificationType.Info => UIColors.Get("LightlessPurple"),
            NotificationType.Warning => UIColors.Get("LightlessYellow"),
            NotificationType.Error => UIColors.Get("DimRed"),
            NotificationType.PairRequest => UIColors.Get("LightlessBlue"),
            NotificationType.Download => UIColors.Get("LightlessGreen"),
            NotificationType.Performance => UIColors.Get("LightlessOrange"),

            _ => UIColors.Get("LightlessPurple")
        };
    }
}