// Asset Naming Manager — one finding.
using System;

namespace AssetNamingManager
{
    /// <summary>
    /// A single problem found on a single asset. One asset can produce several of these
    /// (wrong prefix *and* wrong folder), and the fixer merges them back together before renaming.
    /// </summary>
    [Serializable]
    public class AssetNamingViolation
    {
        /// <summary>Unity-style asset path, e.g. <c>Assets/Art/player run.png</c>.</summary>
        public string assetPath;

        /// <summary>Asset GUID — survives renames, so the UI uses it as the stable row key.</summary>
        public string guid;

        /// <summary>File name without extension.</summary>
        public string assetName;

        /// <summary>Lower-case extension including the dot, e.g. <c>.png</c>. Empty for folders.</summary>
        public string extension;

        /// <summary>Short Unity type name, e.g. <c>Texture2D</c>. <c>Folder</c> for directories.</summary>
        public string typeName;

        /// <summary>What went wrong.</summary>
        public ViolationKind kind;

        /// <summary>How loudly to complain.</summary>
        public NamingSeverity severity;

        /// <summary>Display name of the rule that fired. Empty for project-wide checks.</summary>
        public string ruleName;

        /// <summary>One-line summary shown in the list and in the console.</summary>
        public string message;

        /// <summary>The longer "why and how to fix" text shown in the details pane.</summary>
        public string detail;

        /// <summary>Proposed file name without extension, or null when the Cop cannot guess one.</summary>
        public string suggestedName;

        /// <summary>Proposed destination folder, or null when the asset is already in the right place.</summary>
        public string suggestedFolder;

        /// <summary>True when applying the fix would move the asset to a different folder.</summary>
        public bool IsMove
        {
            get { return !string.IsNullOrEmpty(suggestedFolder); }
        }

        /// <summary>True when applying the fix would change the file name.</summary>
        public bool IsRename
        {
            get { return !string.IsNullOrEmpty(suggestedName) && suggestedName != assetName; }
        }

        /// <summary>True when the Cop has a concrete change it can apply for you.</summary>
        public bool CanAutoFix
        {
            get { return IsRename || IsMove; }
        }

        /// <summary>Folder the asset currently lives in.</summary>
        public string Directory
        {
            get
            {
                if (string.IsNullOrEmpty(assetPath)) return string.Empty;
                int slash = assetPath.LastIndexOf('/');
                return slash < 0 ? string.Empty : assetPath.Substring(0, slash);
            }
        }

        /// <summary>The full path the asset would have after the fix is applied.</summary>
        public string ResolvedPath
        {
            get
            {
                string dir = IsMove ? GlobMatcher.NormalizePath(suggestedFolder) : Directory;
                string name = IsRename ? suggestedName : assetName;
                return string.IsNullOrEmpty(dir) ? name + extension : dir + "/" + name + extension;
            }
        }

        /// <summary>Human label for <see cref="kind"/>, used as a filter chip and column value.</summary>
        public string KindLabel
        {
            get { return Describe(kind); }
        }

        /// <summary>Human label for a <see cref="ViolationKind"/>.</summary>
        public static string Describe(ViolationKind kind)
        {
            switch (kind)
            {
                case ViolationKind.MissingPrefix:      return "Missing prefix";
                case ViolationKind.MissingSuffix:      return "Missing suffix";
                case ViolationKind.ConventionMismatch: return "Wrong casing";
                case ViolationKind.IllegalCharacter:   return "Illegal character";
                case ViolationKind.WrongFolder:        return "Wrong folder";
                case ViolationKind.ForbiddenFolder:    return "Forbidden folder";
                case ViolationKind.DuplicateName:      return "Duplicate name";
                case ViolationKind.TooLong:            return "Name too long";
                case ViolationKind.TooShort:           return "Name too short";
                case ViolationKind.RegexMismatch:      return "Pattern mismatch";
                case ViolationKind.RedundantToken:     return "Junk word";
                case ViolationKind.NumberPadding:      return "Number padding";
                case ViolationKind.LooseInRoot:        return "Loose in root";
                case ViolationKind.EmptyFolder:        return "Empty folder";
                case ViolationKind.FolderNaming:       return "Folder naming";
                case ViolationKind.PathTooLong:        return "Path too long";
                default:                               return kind.ToString();
            }
        }

        /// <inheritdoc />
        public override string ToString()
        {
            return assetPath + " — " + message;
        }
    }
}
