using System;

namespace StellaOps.Feedser.Models;

/// <summary>
/// Helpers for deriving normalized version rules from affected version ranges.
/// </summary>
public static class AffectedVersionRangeExtensions
{
    public static NormalizedVersionRule? ToNormalizedVersionRule(this AffectedVersionRange? range, string? notes = null)
    {
        if (range is null)
        {
            return null;
        }

        var primitives = range.Primitives;

        var semVerRule = primitives?.SemVer?.ToNormalizedVersionRule(notes);
        if (semVerRule is not null)
        {
            return semVerRule;
        }

        var nevraRule = primitives?.Nevra?.ToNormalizedVersionRule(notes);
        if (nevraRule is not null)
        {
            return nevraRule;
        }

        var evrRule = primitives?.Evr?.ToNormalizedVersionRule(notes);
        if (evrRule is not null)
        {
            return evrRule;
        }

        var scheme = Validation.TrimToNull(range.RangeKind)?.ToLowerInvariant();
        return scheme switch
        {
            NormalizedVersionSchemes.SemVer => BuildSemVerFallback(range, notes),
            NormalizedVersionSchemes.Nevra => BuildNevraFallback(range, notes),
            NormalizedVersionSchemes.Evr => BuildEvrFallback(range, notes),
            _ => null,
        };
    }

    private static NormalizedVersionRule? BuildSemVerFallback(AffectedVersionRange range, string? notes)
    {
        var min = Validation.TrimToNull(range.IntroducedVersion);
        var max = Validation.TrimToNull(range.FixedVersion);
        var last = Validation.TrimToNull(range.LastAffectedVersion);
        var resolvedNotes = Validation.TrimToNull(notes);

        if (string.IsNullOrEmpty(min) && string.IsNullOrEmpty(max) && string.IsNullOrEmpty(last))
        {
            return null;
        }

        if (!string.IsNullOrEmpty(max))
        {
            return new NormalizedVersionRule(
                NormalizedVersionSchemes.SemVer,
                NormalizedVersionRuleTypes.Range,
                min: min,
                minInclusive: min is null ? null : true,
                max: max,
                maxInclusive: false,
                notes: resolvedNotes);
        }

        if (!string.IsNullOrEmpty(last))
        {
            return new NormalizedVersionRule(
                NormalizedVersionSchemes.SemVer,
                NormalizedVersionRuleTypes.LessThanOrEqual,
                max: last,
                maxInclusive: true,
                notes: resolvedNotes);
        }

        if (!string.IsNullOrEmpty(min))
        {
            return new NormalizedVersionRule(
                NormalizedVersionSchemes.SemVer,
                NormalizedVersionRuleTypes.GreaterThanOrEqual,
                min: min,
                minInclusive: true,
                notes: resolvedNotes);
        }

        return null;
    }

    private static NormalizedVersionRule? BuildNevraFallback(AffectedVersionRange range, string? notes)
    {
        var resolvedNotes = Validation.TrimToNull(notes);
        var introduced = Validation.TrimToNull(range.IntroducedVersion);
        var fixedVersion = Validation.TrimToNull(range.FixedVersion);
        var lastAffected = Validation.TrimToNull(range.LastAffectedVersion);

        if (!string.IsNullOrEmpty(introduced) && !string.IsNullOrEmpty(fixedVersion))
        {
            return new NormalizedVersionRule(
                NormalizedVersionSchemes.Nevra,
                NormalizedVersionRuleTypes.Range,
                min: introduced,
                minInclusive: true,
                max: fixedVersion,
                maxInclusive: false,
                notes: resolvedNotes);
        }

        if (!string.IsNullOrEmpty(introduced) && !string.IsNullOrEmpty(lastAffected))
        {
            return new NormalizedVersionRule(
                NormalizedVersionSchemes.Nevra,
                NormalizedVersionRuleTypes.Range,
                min: introduced,
                minInclusive: true,
                max: lastAffected,
                maxInclusive: true,
                notes: resolvedNotes);
        }

        if (!string.IsNullOrEmpty(introduced))
        {
            return new NormalizedVersionRule(
                NormalizedVersionSchemes.Nevra,
                NormalizedVersionRuleTypes.GreaterThanOrEqual,
                min: introduced,
                minInclusive: true,
                notes: resolvedNotes);
        }

        if (!string.IsNullOrEmpty(fixedVersion))
        {
            return new NormalizedVersionRule(
                NormalizedVersionSchemes.Nevra,
                NormalizedVersionRuleTypes.LessThan,
                max: fixedVersion,
                maxInclusive: false,
                notes: resolvedNotes);
        }

        if (!string.IsNullOrEmpty(lastAffected))
        {
            return new NormalizedVersionRule(
                NormalizedVersionSchemes.Nevra,
                NormalizedVersionRuleTypes.LessThanOrEqual,
                max: lastAffected,
                maxInclusive: true,
                notes: resolvedNotes);
        }

        return null;
    }

    private static NormalizedVersionRule? BuildEvrFallback(AffectedVersionRange range, string? notes)
    {
        var resolvedNotes = Validation.TrimToNull(notes);
        var introduced = Validation.TrimToNull(range.IntroducedVersion);
        var fixedVersion = Validation.TrimToNull(range.FixedVersion);
        var lastAffected = Validation.TrimToNull(range.LastAffectedVersion);

        if (!string.IsNullOrEmpty(introduced) && !string.IsNullOrEmpty(fixedVersion))
        {
            return new NormalizedVersionRule(
                NormalizedVersionSchemes.Evr,
                NormalizedVersionRuleTypes.Range,
                min: introduced,
                minInclusive: true,
                max: fixedVersion,
                maxInclusive: false,
                notes: resolvedNotes);
        }

        if (!string.IsNullOrEmpty(introduced) && !string.IsNullOrEmpty(lastAffected))
        {
            return new NormalizedVersionRule(
                NormalizedVersionSchemes.Evr,
                NormalizedVersionRuleTypes.Range,
                min: introduced,
                minInclusive: true,
                max: lastAffected,
                maxInclusive: true,
                notes: resolvedNotes);
        }

        if (!string.IsNullOrEmpty(introduced))
        {
            return new NormalizedVersionRule(
                NormalizedVersionSchemes.Evr,
                NormalizedVersionRuleTypes.GreaterThanOrEqual,
                min: introduced,
                minInclusive: true,
                notes: resolvedNotes);
        }

        if (!string.IsNullOrEmpty(fixedVersion))
        {
            return new NormalizedVersionRule(
                NormalizedVersionSchemes.Evr,
                NormalizedVersionRuleTypes.LessThan,
                max: fixedVersion,
                maxInclusive: false,
                notes: resolvedNotes);
        }

        if (!string.IsNullOrEmpty(lastAffected))
        {
            return new NormalizedVersionRule(
                NormalizedVersionSchemes.Evr,
                NormalizedVersionRuleTypes.LessThanOrEqual,
                max: lastAffected,
                maxInclusive: true,
                notes: resolvedNotes);
        }

        return null;
    }
}
