// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms.VisualStyles;

namespace System.Windows.Forms;

/// <summary>
///  Renders a modern <see cref="FlatStyle.Flat"/> button with a rectangular body and a single border.
/// </summary>
internal sealed class ModernFlatButtonRenderer : ButtonDarkModeRendererBase
{
    private const int BorderThicknessLogical = 1;
    private const int ContentInsetLogical = 4;
    private const int FocusInsetLogical = 3;

    private static readonly Color s_lightBorder = Color.FromArgb(0xD0, 0xD0, 0xD0);
    private static readonly Color s_darkBorder = Color.FromArgb(0x55, 0x55, 0x55);
    private static readonly Color s_lightNormal = Color.FromArgb(0xFB, 0xFB, 0xFB);
    private static readonly Color s_darkNormal = Color.FromArgb(0x2D, 0x2D, 0x2D);

    private static bool IsDark => Application.IsDarkModeEnabled;

    private int BorderThickness
        => ScaleBorderThickness(Math.Max(1, Scale(BorderThicknessLogical)));

    private protected override Padding PaddingCore => Padding.Empty;

    private protected override bool UseModernStateDefaults => true;

    internal override Padding GetPreferredSizePadding()
        => new(Math.Max(BorderThickness, Scale(ContentInsetLogical)));

    public override Rectangle DrawButtonBackground(
        Graphics graphics,
        Rectangle bounds,
        PushButtonState state,
        bool isDefault,
        bool focused,
        Color backColor)
    {
        GraphicsState? saved = graphics.Save();
        try
        {
            graphics.SmoothingMode = SmoothingMode.Default;

            using (var brush = backColor.GetCachedSolidBrushScope())
            {
                graphics.FillRectangle(brush, bounds);
            }

            int thickness = BorderThickness;
            if (thickness > 0 && bounds.Width > 0 && bounds.Height > 0)
            {
                Color designBorderColor = isDefault
                    ? (IsDark ? Color.White : SystemColors.Highlight)
                    : (IsDark ? s_darkBorder : s_lightBorder);

                using var pen = new Pen(ResolveBorderColor(designBorderColor), thickness)
                {
                    Alignment = PenAlignment.Inset
                };

                graphics.DrawRectangle(pen, bounds.X, bounds.Y, bounds.Width - 1, bounds.Height - 1);
            }
        }
        finally
        {
            if (saved is not null)
            {
                graphics.Restore(saved);
            }
        }

        int inset = Math.Max(BorderThickness, Scale(ContentInsetLogical));
        return Rectangle.Inflate(bounds, -inset, -inset);
    }

    public override void DrawFocusIndicator(Graphics graphics, Rectangle contentBounds, bool isDefault)
    {
        int inset = Scale(FocusInsetLogical);
        Rectangle focusRectangle = Rectangle.Inflate(contentBounds, -inset, -inset);
        if (focusRectangle.Width <= 0 || focusRectangle.Height <= 0)
        {
            return;
        }

        Color focusColor = ResolveBorderColor(IsDark ? Color.White : SystemColors.WindowText);
        using var focusPen = new Pen(focusColor) { DashStyle = DashStyle.Dot };
        graphics.DrawRectangle(focusPen, focusRectangle);
    }

    public override Color GetTextColor(PushButtonState state, bool isDefault, Color backColor)
    {
        return state == PushButtonState.Disabled
            ? ModernControlColorMath.GetDisabledForeColor(backColor)
            : ModernButtonColorMath.GetReadableForeColor(backColor);
    }

    public override Color GetBackgroundColor(PushButtonState state, bool isDefault)
    {
        if (state == PushButtonState.Disabled)
        {
            return ModernControlColorMath.GetDisabledSurfaceColor();
        }

        if (isDefault)
        {
            return ModernButtonColorMath.GetDefaultButtonColor(state);
        }

        Color baseColor = IsDark ? s_darkNormal : s_lightNormal;

        return state switch
        {
            PushButtonState.Hot => DeriveHoverColor(baseColor),
            PushButtonState.Pressed => DerivePressedColor(baseColor),
            _ => baseColor
        };
    }
}
