/* This file is generated by DeepSeek */

using System;
using System.Windows;
using System.Windows.Controls;

namespace PCL.Core.UI.Controls;

/// <summary>
/// 瀑布流布局模式
/// </summary>
public enum WaterfallLayoutMode
{
    /// <summary>
    /// 固定列数模式，使用 ColumnCount 属性指定列数
    /// </summary>
    FixedColumns,

    /// <summary>
    /// 自适应模式，根据可用宽度和 MaxItemWidth 自动计算列数
    /// </summary>
    AutoFit
}

public class WaterfallPanel : Panel
{
    // 私有字段，存储 Measure 阶段计算出的实际列数（用于 Arrange 阶段）
    private int _computedColumnCount;

    #region 依赖属性

    /// <summary>
    /// 布局模式（固定列数 / 自适应）
    /// </summary>
    public WaterfallLayoutMode LayoutMode
    {
        get { return (WaterfallLayoutMode)GetValue(LayoutModeProperty); }
        set { SetValue(LayoutModeProperty, value); }
    }

    public static readonly DependencyProperty LayoutModeProperty =
        DependencyProperty.Register(nameof(LayoutMode), typeof(WaterfallLayoutMode), typeof(WaterfallPanel),
            new FrameworkPropertyMetadata(WaterfallLayoutMode.FixedColumns, FrameworkPropertyMetadataOptions.AffectsMeasure));

    /// <summary>
    /// 固定列数（仅在 LayoutMode = FixedColumns 时生效）
    /// </summary>
    public int ColumnCount
    {
        get { return (int)GetValue(ColumnCountProperty); }
        set { SetValue(ColumnCountProperty, value); }
    }

    public static readonly DependencyProperty ColumnCountProperty =
        DependencyProperty.Register(nameof(ColumnCount), typeof(int), typeof(WaterfallPanel),
            new FrameworkPropertyMetadata(2, FrameworkPropertyMetadataOptions.AffectsMeasure));

    /// <summary>
    /// 列间距
    /// </summary>
    public double ColumnSpacing
    {
        get { return (double)GetValue(ColumnSpacingProperty); }
        set { SetValue(ColumnSpacingProperty, value); }
    }

    public static readonly DependencyProperty ColumnSpacingProperty =
        DependencyProperty.Register(nameof(ColumnSpacing), typeof(double), typeof(WaterfallPanel),
            new FrameworkPropertyMetadata(5.0, FrameworkPropertyMetadataOptions.AffectsMeasure));

    /// <summary>
    /// 行间距
    /// </summary>
    public double RowSpacing
    {
        get { return (double)GetValue(RowSpacingProperty); }
        set { SetValue(RowSpacingProperty, value); }
    }

    public static readonly DependencyProperty RowSpacingProperty =
        DependencyProperty.Register(nameof(RowSpacing), typeof(double), typeof(WaterfallPanel),
            new FrameworkPropertyMetadata(0.0, FrameworkPropertyMetadataOptions.AffectsMeasure));

    /// <summary>
    /// 项的最大宽度（仅在 LayoutMode = AutoFit 时生效）
    /// </summary>
    public double MaxItemWidth
    {
        get { return (double)GetValue(MaxItemWidthProperty); }
        set { SetValue(MaxItemWidthProperty, value); }
    }

    public static readonly DependencyProperty MaxItemWidthProperty =
        DependencyProperty.Register(nameof(MaxItemWidth), typeof(double), typeof(WaterfallPanel),
            new FrameworkPropertyMetadata(100.0, FrameworkPropertyMetadataOptions.AffectsMeasure));

    #endregion

    protected override Size MeasureOverride(Size availableSize)
    {
        // 1. 确定列数
        int columnCount;
        if (LayoutMode == WaterfallLayoutMode.FixedColumns)
        {
            columnCount = ColumnCount;
        }
        else // AutoFit
        {
            if (double.IsInfinity(availableSize.Width) || double.IsNaN(availableSize.Width))
            {
                // 宽度无限时，回退到固定列数模式（使用 ColumnCount 作为后备）
                columnCount = ColumnCount;
            }
            else
            {
                double effectiveMaxWidth = MaxItemWidth > 0 ? MaxItemWidth : 100; // 防御性处理
                double slotWidth = effectiveMaxWidth + ColumnSpacing;
                columnCount = Math.Max(1, (int)Math.Floor((availableSize.Width + ColumnSpacing) / slotWidth));
            }
        }
        _computedColumnCount = columnCount;

        // 2. 计算每列的实际宽度
        double colWidth = (availableSize.Width - (columnCount - 1) * ColumnSpacing) / columnCount;
        colWidth = Math.Max(0, colWidth); // 避免负宽度

        // 3. 记录每列的当前高度（用于测量时决定元素放入哪一列）
        double[] colHeights = new double[columnCount];

        // 4. 测量所有子元素
        foreach (UIElement child in InternalChildren)
        {
            // 约束子元素宽度为列宽，高度不限
            child.Measure(new Size(colWidth, double.PositiveInfinity));
            Size desiredSize = child.DesiredSize;

            // 找到当前高度最小的列
            int minColIndex = _GetMinHeightColumnIndex(colHeights);
            double y = colHeights[minColIndex]; // 当前列已占高度，即新元素的 Y 坐标

            // 更新该列高度：加上元素高度和行间距（为下一个元素预留）
            colHeights[minColIndex] += desiredSize.Height + RowSpacing;
        }

        // 5. 计算面板所需总高度（取最高列的实际内容高度，需减去最后一个多余的行间距）
        double totalHeight = 0;
        for (int i = 0; i < colHeights.Length; i++)
        {
            if (colHeights[i] > 0)
                totalHeight = Math.Max(totalHeight, colHeights[i] - RowSpacing);
            else
                totalHeight = Math.Max(totalHeight, colHeights[i]);
        }

        return new Size(availableSize.Width, totalHeight);
    }

    protected override Size ArrangeOverride(Size finalSize)
    {
        if (_computedColumnCount <= 0) return finalSize;

        // 使用 Measure 阶段确定的列数，但根据 finalSize 重新计算列宽（保证填满可用宽度）
        double colWidth = (finalSize.Width - (_computedColumnCount - 1) * ColumnSpacing) / _computedColumnCount;
        colWidth = Math.Max(0, colWidth);

        double[] colHeights = new double[_computedColumnCount];

        foreach (UIElement child in InternalChildren)
        {
            int colIndex = _GetMinHeightColumnIndex(colHeights);
            double x = colIndex * (colWidth + ColumnSpacing);
            double y = colHeights[colIndex];

            child.Arrange(new Rect(new Point(x, y), new Size(colWidth, child.DesiredSize.Height)));

            // 更新该列高度：加上元素高度和行间距（为下一个元素定位）
            colHeights[colIndex] += child.DesiredSize.Height + RowSpacing;
        }

        return finalSize;
    }

    /// <summary>
    /// 获取当前高度最小的列索引
    /// </summary>
    private int _GetMinHeightColumnIndex(double[] colHeights)
    {
        int minIndex = 0;
        double minHeight = colHeights[0];
        for (int i = 1; i < colHeights.Length; i++)
        {
            if (colHeights[i] < minHeight)
            {
                minHeight = colHeights[i];
                minIndex = i;
            }
        }
        return minIndex;
    }
}