using System.Reflection;
using Quadarax.Foundation.Core.Reflection.Extensions;

namespace Quadarax.Foundation.Core.Reflection
{
    public class QualifiedName
    {
        #region *** Constants ***
        private const char CC_SEPARATOR = ',';
        #endregion

        #region *** Public Properties ***
        // ReSharper disable MemberCanBePrivate.Global
        // ReSharper disable UnusedAutoPropertyAccessor.Global
        public string Name { get; private set; }
        public string? Assembly { get; private set; }
        public string? Culture { get; private set; }
        public string Token { get; private set; }
        public string Version { get; private set; }
        public string AssemblyFullName { get; private set; }
        // ReSharper restore UnusedAutoPropertyAccessor.Global
        // ReSharper restore MemberCanBePrivate.Global
        #endregion
        #region *** Constructors ***
        public QualifiedName(string sReflectionQualifiedName)
        {
            Name = string.Empty;
            Token = string.Empty;
            Version = string.Empty;
            AssemblyFullName = string.Empty;
            var aParts = sReflectionQualifiedName.Split(CC_SEPARATOR)
                            .Select(x => x.Trim())
                            .ToList();

            if (aParts.Count==0)
                return;
            if (aParts.Count==1)
            {
                //jedna se o bud o codebase nebo assembly
                bool bCodebase = false;
                try
                {
                    var oType = Type.GetType(aParts[0].Trim(), true);
                    if (oType == null)
                        throw new Exception("Type is null");
                    SetupProperties(oType.Assembly.GetName());
                    bCodebase = true;
                }
                catch{}
                if (bCodebase)
                {
                    //codebase
                    Name = aParts[0].Trim();
                }
                else
                {
                    //assembly
                    try
                    {                        
                        SetupProperties(new AssemblyName(aParts[0].Trim()));
                    }
                    catch (System.Exception e)
                    {
                        ThrowCannotParse(sReflectionQualifiedName, e);
                    }
                }

            }
            if (aParts.Count > 1)
            {
                //jedna se bud o codebase, assembly nebo assembly
                try
                {
                    if (aParts[1].IndexOf('=') > 0)
                    {
                        //assembly
                        SetupProperties(new AssemblyName(string.Join(CC_SEPARATOR.ToString() , aParts)));
                    }
                    else
                    {
                        //codebase, assembly
                        SetupProperties(new AssemblyName(string.Join(CC_SEPARATOR.ToString(), aParts.Skip(1))));
                        Name = aParts[0].Trim();
                    }
                }
                catch (System.Exception e)
                {
                    ThrowCannotParse(sReflectionQualifiedName, e);
                }                
            }
            

            
        }
        #endregion
        #region *** Public Operations ***
        public string GetQualifiedNameWithoutVersion()
        {
            return Name + CC_SEPARATOR + " " + Assembly;
        }

        public bool LiteEquals(QualifiedName oCompareObject)
        {
            return oCompareObject.Assembly == Assembly && oCompareObject.Name == Name;
        }
        #endregion
        #region *** Private Operations ***
        private void SetupProperties(AssemblyName? oName)
        {
            if (oName == null)
                throw new ArgumentNullException(nameof(oName));

            Assembly = oName.Name;
            AssemblyFullName = oName.FullName;
            Culture = oName.CultureName;
            Token = oName.GetPublicKeyTokenString();
            Version = oName.Version!=null ? oName.Version.ToString() : string.Empty;            
        
        }
        private void ThrowCannotParse(string sReflectionQualifiedName, System.Exception oInnerException)
        {
            throw new ArgumentException($"Cannot parse QualifiedName '{sReflectionQualifiedName}'!", oInnerException);
        }
        #endregion
    }
}
