using System;

namespace StellaOps.Feedser.Models;

/// <summary>
/// Helper extensions for converting <see cref="SemVerPrimitive"/> values into normalized rules.
/// </summary>
public static class SemVerPrimitiveExtensions
{
    public static NormalizedVersionRule? ToNormalizedVersionRule(this SemVerPrimitive? primitive, string? notes = null)
    {
        if (primitive is null)
        {
            return null;
        }

        var trimmedNotes = Validation.TrimToNull(notes);
        var constraintNotes = Validation.TrimToNull(primitive.ConstraintExpression);
        var resolvedNotes = trimmedNotes ?? constraintNotes;
        var scheme = NormalizedVersionSchemes.SemVer;

        if (!string.IsNullOrWhiteSpace(primitive.ExactValue))
        {
            return new NormalizedVersionRule(
                scheme,
                NormalizedVersionRuleTypes.Exact,
                value: primitive.ExactValue,
                notes: resolvedNotes);
        }

        var introduced = Validation.TrimToNull(primitive.Introduced);
        var fixedVersion = Validation.TrimToNull(primitive.Fixed);
        var lastAffected = Validation.TrimToNull(primitive.LastAffected);

        if (!string.IsNullOrEmpty(introduced) && !string.IsNullOrEmpty(fixedVersion))
        {
            return new NormalizedVersionRule(
                scheme,
                NormalizedVersionRuleTypes.Range,
                min: introduced,
                minInclusive: primitive.IntroducedInclusive,
                max: fixedVersion,
                maxInclusive: primitive.FixedInclusive,
                notes: resolvedNotes);
        }

        if (!string.IsNullOrEmpty(introduced) && string.IsNullOrEmpty(fixedVersion) && !string.IsNullOrEmpty(lastAffected))
        {
            return new NormalizedVersionRule(
                scheme,
                NormalizedVersionRuleTypes.Range,
                min: introduced,
                minInclusive: primitive.IntroducedInclusive,
                max: lastAffected,
                maxInclusive: primitive.LastAffectedInclusive,
                notes: resolvedNotes);
        }

        if (!string.IsNullOrEmpty(introduced) && string.IsNullOrEmpty(fixedVersion) && string.IsNullOrEmpty(lastAffected))
        {
            var type = primitive.IntroducedInclusive ? NormalizedVersionRuleTypes.GreaterThanOrEqual : NormalizedVersionRuleTypes.GreaterThan;
            return new NormalizedVersionRule(
                scheme,
                type,
                min: introduced,
                minInclusive: primitive.IntroducedInclusive,
                notes: resolvedNotes);
        }

        if (!string.IsNullOrEmpty(fixedVersion))
        {
            var type = primitive.FixedInclusive ? NormalizedVersionRuleTypes.LessThanOrEqual : NormalizedVersionRuleTypes.LessThan;
            return new NormalizedVersionRule(
                scheme,
                type,
                max: fixedVersion,
                maxInclusive: primitive.FixedInclusive,
                notes: resolvedNotes);
        }

        if (!string.IsNullOrEmpty(lastAffected))
        {
            var type = primitive.LastAffectedInclusive ? NormalizedVersionRuleTypes.LessThanOrEqual : NormalizedVersionRuleTypes.LessThan;
            return new NormalizedVersionRule(
                scheme,
                type,
                max: lastAffected,
                maxInclusive: primitive.LastAffectedInclusive,
                notes: resolvedNotes);
        }

        if (!string.IsNullOrWhiteSpace(primitive.ConstraintExpression))
        {
            return new NormalizedVersionRule(
                scheme,
                NormalizedVersionRuleTypes.Range,
                notes: resolvedNotes);
        }

        return null;
    }
}
