// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#nullable disable

using System;

namespace Microsoft.AspNetCore.Razor.Language;

public abstract class RazorDiagnostic : IEquatable<RazorDiagnostic>, IFormattable
{
    internal static readonly RazorDiagnostic[] EmptyArray = Array.Empty<RazorDiagnostic>();
    internal static readonly object[] EmptyArgs = Array.Empty<object>();

    public abstract string Id { get; }

    public abstract RazorDiagnosticSeverity Severity { get; }

    public abstract SourceSpan Span { get; }

    public abstract string GetMessage(IFormatProvider formatProvider);

    public string GetMessage() => GetMessage(null);

    public abstract bool Equals(RazorDiagnostic other);

    public abstract override int GetHashCode();

    public static RazorDiagnostic Create(RazorDiagnosticDescriptor descriptor, SourceSpan span)
    {
        if (descriptor == null)
        {
            throw new ArgumentNullException(nameof(descriptor));
        }

        return new DefaultRazorDiagnostic(descriptor, span, EmptyArgs);
    }

    public static RazorDiagnostic Create(RazorDiagnosticDescriptor descriptor, SourceSpan span, params object[] args)
    {
        if (descriptor == null)
        {
            throw new ArgumentNullException(nameof(descriptor));
        }

        return new DefaultRazorDiagnostic(descriptor, span, args);
    }

    public override string ToString()
    {
        return ((IFormattable)this).ToString(null, null);
    }

    public override bool Equals(object obj)
    {
        var other = obj as RazorDiagnostic;
        return other == null ? false : Equals(other);
    }

    string IFormattable.ToString(string ignore, IFormatProvider formatProvider)
    {
        // Our indices are 0-based, but we we want to print them as 1-based.
        return $"{Span.FilePath}({Span.LineIndex + 1},{Span.CharacterIndex + 1}): {Severity} {Id}: {GetMessage(formatProvider)}";
    }
}
