namespace Kompas.Mcp.Core.Modeling;

/// <summary>Чистые помощники геометрии эскиза: маппинги контракта в параметры COM и валидация.</summary>
public static class SketchGeometry
{
    /// <summary>Направление дуги для ksArcByAngle: против часовой → 1, по часовой → -1.</summary>
    public static short ArcDirection(bool counterClockwise) => (short)(counterClockwise ? 1 : -1);

    /// <summary>describe для ksRegularPolygon: вписанный (вершины на окружности) → false; описанный → true.</summary>
    public static bool PolygonDescribe(bool inscribed) => !inscribed;

    /// <summary>Направление достройки ребра жёсткости (ksRibSideEnum): left=0, right=1, up=2, down=3.</summary>
    public static short RibSide(string side) => side?.Trim().ToLowerInvariant() switch
    {
        "left" => 0,
        "right" => 1,
        "up" => 2,
        "down" => 3,
        _ => throw new ArgumentException(
            $"Неизвестное направление ребра: '{side}'. Ожидается left|right|up|down.", nameof(side)),
    };

    /// <summary>Требовать строго положительное значение (радиус, полуось).</summary>
    public static void RequirePositive(double value, string paramName)
    {
        if (!(value > 0))
            throw new ArgumentOutOfRangeException(paramName, value, "Значение должно быть > 0.");
    }

    /// <summary>Требовать >= 3 вершин для правильного многоугольника.</summary>
    public static void RequireVertexCount(int count)
    {
        if (count < 3)
            throw new ArgumentOutOfRangeException(nameof(count), count, "Число вершин должно быть >= 3.");
    }

    /// <summary>Требовать целое значение не меньше <paramref name="min"/> (например, число экземпляров массива).</summary>
    public static void RequireMin(int value, int min, string paramName)
    {
        if (value < min)
            throw new ArgumentOutOfRangeException(paramName, value, $"Значение должно быть >= {min}.");
    }

    /// <summary>Требовать угол уклона: конечный и строго в диапазоне (0; 90) градусов.</summary>
    public static void RequireDraftAngle(double angle, string paramName)
    {
        if (!double.IsFinite(angle) || angle <= 0 || angle >= 90)
            throw new ArgumentOutOfRangeException(paramName, angle, "Угол уклона должен быть в (0; 90) градусов.");
    }

    /// <summary>Валидировать список точек: не null, минимум <paramref name="min"/>, все координаты конечны.</summary>
    public static void RequirePoints(IReadOnlyList<(double x, double y)> points, int min, string paramName)
    {
        ArgumentNullException.ThrowIfNull(points, paramName);
        if (points.Count < min)
            throw new ArgumentException($"Нужно минимум {min} точек, передано {points.Count}.", paramName);
        for (int i = 0; i < points.Count; i++)
            if (!double.IsFinite(points[i].x) || !double.IsFinite(points[i].y))
                throw new ArgumentException($"Точка [{i}] имеет неконечную координату.", paramName);
    }
}
