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

using System;
using System.Diagnostics;

namespace Microsoft.AspNetCore.Razor.Language
{
	// Note: RazorSDK is aware of version monikers such as "latest", and "experimental". Update it if we introduce new monikers.
	[DebuggerDisplay( "{" + nameof( DebuggerToString ) + "(),nq}" )]
	public sealed class RazorLanguageVersion : IEquatable<RazorLanguageVersion>, IComparable<RazorLanguageVersion>
	{
		public static readonly RazorLanguageVersion Version_1_0 = new RazorLanguageVersion( 1, 0 );

		public static readonly RazorLanguageVersion Version_1_1 = new RazorLanguageVersion( 1, 1 );

		public static readonly RazorLanguageVersion Version_2_0 = new RazorLanguageVersion( 2, 0 );

		public static readonly RazorLanguageVersion Version_2_1 = new RazorLanguageVersion( 2, 1 );

		public static readonly RazorLanguageVersion Version_3_0 = new RazorLanguageVersion( 3, 0 );

		public static readonly RazorLanguageVersion Version_5_0 = new RazorLanguageVersion( 5, 0 );

		public static readonly RazorLanguageVersion Version_6_0 = new RazorLanguageVersion( 6, 0 );

		public static readonly RazorLanguageVersion Latest = Version_6_0;

		public static readonly RazorLanguageVersion Experimental = new RazorLanguageVersion( 1337, 1337 );

		public static bool TryParse( string languageVersion, out RazorLanguageVersion version )
		{
			if ( languageVersion == null )
			{
				throw new ArgumentNullException( nameof( languageVersion ) );
			}

			if ( string.Equals( languageVersion, "latest", StringComparison.OrdinalIgnoreCase ) )
			{
				version = Latest;
				return true;
			}
			else if ( string.Equals( languageVersion, "experimental", StringComparison.OrdinalIgnoreCase ) )
			{
				version = Experimental;
				return true;
			}
			else if ( languageVersion == "6.0" )
			{
				version = Version_6_0;
				return true;
			}
			else if ( languageVersion == "5.0" )
			{
				version = Version_5_0;
				return true;
			}
			else if ( languageVersion == "3.0" )
			{
				version = Version_3_0;
				return true;
			}
			else if ( languageVersion == "2.1" )
			{
				version = Version_2_1;
				return true;
			}
			else if ( languageVersion == "2.0" )
			{
				version = Version_2_0;
				return true;
			}
			else if ( languageVersion == "1.1" )
			{
				version = Version_1_1;
				return true;
			}
			else if ( languageVersion == "1.0" )
			{
				version = Version_1_0;
				return true;
			}

			version = null;
			return false;
		}

		public static RazorLanguageVersion Parse( string languageVersion )
		{
			if ( languageVersion == null )
			{
				throw new ArgumentNullException( nameof( languageVersion ) );
			}

			if ( TryParse( languageVersion, out var parsed ) )
			{
				return parsed;
			}

			throw new InvalidOperationException();
		}

		// Don't want anyone else constructing language versions.
		private RazorLanguageVersion( int major, int minor )
		{
			Major = major;
			Minor = minor;
		}

		public int Major { get; }

		public int Minor { get; }

		public int CompareTo( RazorLanguageVersion other )
		{
			if ( other == null )
			{
				throw new ArgumentNullException( nameof( other ) );
			}

			var result = Major.CompareTo( other.Major );
			if ( result != 0 )
			{
				return result;
			}

			return Minor.CompareTo( other.Minor );
		}

		public bool Equals( RazorLanguageVersion other )
		{
			if ( other == null )
			{
				return false;
			}

			// We're the only one who can create RazorLanguageVersions so reference equality is sufficient.
			return ReferenceEquals( this, other );
		}

		public override int GetHashCode()
		{
			// We don't need to do anything special for our hash code since reference equality is what we're going for.
			return base.GetHashCode();
		}

		public override string ToString() => $"{Major}.{Minor}";

		private string DebuggerToString() => $"Razor '{Major}.{Minor}'";
	}
}
