using System.Globalization;

namespace ZB.MOM.WW.ScadaBridge.CentralUI.Components.Shared;

/// <summary>
/// Converts a <see cref="TimeSpan"/> to and from the number+unit pair behind a
/// duration input (milliseconds / seconds / minutes). A blank or non-positive
/// number represents "unset" (a <c>null</c> duration).
/// </summary>
internal static class DurationInput
{
    /// <summary>The unit tokens a duration input offers, smallest first.</summary>
    internal static readonly string[] Units = { "ms", "sec", "min" };

    /// <summary>
    /// Splits a duration into the largest whole unit that represents it exactly.
    /// A null or non-positive duration yields a blank value and the default
    /// <c>sec</c> unit.
    /// </summary>
    /// <param name="duration">The duration to split, or null for unset.</param>
    /// <returns>A tuple of the numeric string and unit token (ms/sec/min), or <c>(null, "sec")</c> for null or non-positive input.</returns>
    internal static (string? Value, string Unit) Split(TimeSpan? duration)
    {
        if (duration is not { } d || d <= TimeSpan.Zero) return (null, "sec");

        var ms = (long)d.TotalMilliseconds;
        if (ms % 60000 == 0) return ((ms / 60000).ToString(CultureInfo.InvariantCulture), "min");
        if (ms % 1000 == 0) return ((ms / 1000).ToString(CultureInfo.InvariantCulture), "sec");
        return (ms.ToString(CultureInfo.InvariantCulture), "ms");
    }

    /// <summary>
    /// Composes a number+unit pair into a duration. A blank, unparseable, or
    /// non-positive value yields <c>null</c> (unset).
    /// </summary>
    /// <param name="value">The numeric string entered by the user.</param>
    /// <param name="unit">The selected unit token (ms, sec, or min).</param>
    /// <returns>The composed <see cref="TimeSpan"/>, or <c>null</c> for blank, unparseable, or non-positive input.</returns>
    internal static TimeSpan? Compose(string? value, string unit)
    {
        if (!long.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var n)
            || n <= 0)
        {
            return null;
        }

        var factorMs = unit switch
        {
            "min" => 60000L,
            "ms" => 1L,
            _ => 1000L,
        };
        return TimeSpan.FromMilliseconds(n * factorMs);
    }
}
