using System;
using System.Collections.Generic;
using System.Linq;
using Semver;

namespace UnityEditor.PackageManager.UI
{
    [Serializable]
    internal class PackageInfo : IEquatable<PackageInfo>
    {
        // Module package.json files contain a documentation url embedded in the description.
        // We parse that to have the "View Documentation" button direct to it, instead of showing
        // the link in the description text.
        private const string builtinPackageDocsUrlKey = "Scripting API: ";

        public string Name;
        public string DisplayName;
        private string _PackageId;
        public SemVersion Version;
        public string Description;
        public string Category;
        public PackageState State;
        public bool IsCurrent;
        public bool IsLatest;
        public string Group;
        public PackageSource Origin;
        public List<Error> Errors;
        public bool IsVerified;
        public string Author;

        public PackageManager.PackageInfo Info { get; set; }
        
        public string PackageId {
            get
            {
                if (!string.IsNullOrEmpty(_PackageId )) 
                    return _PackageId;
                return string.Format("{0}@{1}", Name.ToLower(), Version);
            }
            set
            {
                _PackageId = value;
            }
        }

        // This will always be <name>@<version>, even for an embedded package.
        public string VersionId { get { return string.Format("{0}@{1}", Name.ToLower(), Version); } }
        public string ShortVersionId { get { return string.Format("{0}@{1}", Name.ToLower(), Version.ShortVersion()); } }

        public string BuiltInDescription { get {
            if (IsBuiltIn)
                return string.Format("This built in package controls the presence of the {0} module.", DisplayName);
            else
                return Description.Split(new[] {builtinPackageDocsUrlKey}, StringSplitOptions.None)[0];
        } }

        // Method content must be matched in package-manager-doctools extension
        public static string GetPackageUrlRedirect(string packageName)
        {
            var redirectUrl = "";
            if (packageName == "com.unity.ads")
                redirectUrl = "https://docs.unity3d.com/Manual/UnityAds.html";
            else if  (packageName == "com.unity.analytics")
                redirectUrl = "https://docs.unity3d.com/Manual/UnityAnalytics.html";
            else if  (packageName == "com.unity.purchasing")
                redirectUrl = "https://docs.unity3d.com/Manual/UnityIAP.html";
            else if  (packageName == "com.unity.standardevents")
                redirectUrl = "https://docs.unity3d.com/Manual/UnityAnalyticsStandardEvents.html";
            else if  (packageName == "com.unity.xiaomi")
                redirectUrl = "https://unity3d.com/cn/partners/xiaomi/guide";
            else if (packageName == "com.unity.shadergraph")
                redirectUrl = "https://github.com/Unity-Technologies/ShaderGraph/wiki";
            else if (packageName == "com.unity.collab-proxy")
                redirectUrl = "https://docs.unity3d.com/Manual/UnityCollaborate.html";

            return redirectUrl;
        }

        public bool RedirectsToManual(PackageInfo packageInfo)
        {
            return !string.IsNullOrEmpty(GetPackageUrlRedirect(packageInfo.Name));
        }

        public bool HasChangelog(PackageInfo packageInfo)
        {
            // Packages with no docs have no third party notice
            return !RedirectsToManual(packageInfo);
        }

        public string GetDocumentationUrl()
        {
            if (IsBuiltIn)
            {
                if (!string.IsNullOrEmpty(Description))
                {
                    var split = Description.Split(new[] {builtinPackageDocsUrlKey}, StringSplitOptions.None);
                    if (split.Length > 1)
                        return split[1];
                }
            }
            return string.Format("http://docs.unity3d.com/Packages/{0}/index.html", ShortVersionId);
        }

        public string GetChangelogUrl()
        {
            return string.Format("http://docs.unity3d.com/Packages/{0}/changelog/CHANGELOG.html", ShortVersionId);
        }

        public string GetLicensesUrl()
        {
            var url = string.Format("http://docs.unity3d.com/Packages/{0}/license/index.html", ShortVersionId);
            if (RedirectsToManual(this))
                url = "https://unity3d.com/legal/licenses/Unity_Companion_License";

            return url;
        }
        
        public bool Equals(PackageInfo other)
        {
            if (other == null) 
                return false;
            if (other == this)
                return true;
            
            return Name == other.Name && Version == other.Version;
        }

        public override int GetHashCode()
        {
            return PackageId.GetHashCode();
        }

        public bool HasVersionTag(string tag)
        {
            if (string.IsNullOrEmpty(Version.Prerelease))
                return false;

            return String.Equals(Version.Prerelease.Split('.').First(), tag, StringComparison.CurrentCultureIgnoreCase);
        }

        public bool HasVersionTag(PackageTag tag)
        {
            return HasVersionTag(tag.ToString());
        }

        // Is it a pre-release (alpha/beta/experimental/preview)?
        //        Current logic is any tag is considered pre-release, except recommended
        public bool IsPreRelease
        {
            get { return !string.IsNullOrEmpty(Version.Prerelease) || Version.Major == 0; }
        }

        public bool IsPreview
        {
            get { return HasVersionTag(PackageTag.preview) || Version.Major == 0; }
        }

        // A version is user visible if it has a supported tag (or no tag at all)
        public bool IsUserVisible
        {
            get { return IsCurrent || string.IsNullOrEmpty(Version.Prerelease) || HasVersionTag(PackageTag.preview) || IsVerified; }
        }

        public bool IsInDevelopment { get { return Origin == PackageSource.Embedded; } }
        public bool IsLocal { get { return Origin == PackageSource.Local; } }
        public bool IsBuiltIn { get { return Origin == PackageSource.BuiltIn; } }
        
        public string VersionWithoutTag { get { return Version.VersionOnly(); } }
        
        public bool IsVersionLocked
        {
            get { return Origin == PackageSource.Embedded || Origin == PackageSource.Git || Origin == PackageSource.BuiltIn; }
        }

        public bool CanBeRemoved
        {
            get { return Origin == PackageSource.Registry || Origin == PackageSource.BuiltIn || Origin == PackageSource.Local; }
        }
    }
}
