using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using BundleV2;
using UnityEditor;
using UnityEngine;

public static class TextureUtility
{
    public const string t4MControlTextureHeader = "Assets/T4MOBJ/Terrains/Texture/";
    public const string postProcessTextureHeader = "Assets/Plugins/PostProcessing/";

    [MenuItem("ProTool/PurgeAssets/Reimport All Sprites", false, 5)]
    public static void ReimportAllSprites()
    {
        var action = new ReimportSpriteAction(GetAllTexturePaths());
        action.Start();
    }

    [MenuItem("ProTool/PurgeAssets/Get All Non Power2", false, 5)]
    public static void GetAllNonPower2()
    {
        var action = new GetAllNonPowerAction(GetAllTexturePaths());
        action.Start();
    }

    private static HashSet<string> GetNonCompressTextures()
    {
        // 特殊处理T4M相关的法线贴图
        var materials = (from assetPath in AssetDatabase.GetAllAssetPaths()
            where assetPath.StartsWith("Assets/")
            where ".mat" == Path.GetExtension(assetPath)
            let material = AssetDatabase.LoadAssetAtPath<Material>(assetPath)
            where material && material.shader
            let shaderName = material.shader.name
            where shaderName.Contains("/T4M", StringComparison.OrdinalIgnoreCase) ||
                  shaderName.Contains("/T3M", StringComparison.OrdinalIgnoreCase) ||
                  shaderName.Contains("/T2M", StringComparison.OrdinalIgnoreCase)
            select assetPath).ToArray();
        var hashSet = new HashSet<string>();
        for (var i = 0; i < materials.Length; i++)
        {
            EditorUtility.DisplayProgressBar("Collect Textures", string.Format("({0} / {1})", i, materials.Length),
                (float) i / materials.Length);
            var dependencies = AssetDatabase.GetDependencies(materials[i], true);
            foreach (var dependency in dependencies)
                if (EditorAssetConst.textureExtensions.Contains(Path.GetExtension(dependency)))
                    hashSet.Add(dependency);
        }

        var normals = hashSet.ToArray();
        // 重新装入保护系统
        hashSet.Clear();
        for (var i = 0; i < normals.Length; i++)
        {
            EditorUtility.DisplayProgressBar("Get T4M Normals", string.Format("({0} / {1})", i, normals.Length),
                (float) i / normals.Length);
            var textureImporter = AssetImporter.GetAtPath(normals[i]) as TextureImporter;
            if (textureImporter && textureImporter.textureType == TextureImporterType.NormalMap)
                hashSet.Add(normals[i]);
        }

        EditorUtility.ClearProgressBar();
        // 特殊处理T4M的控制贴图
        var controls = from assetPath in AssetDatabase.GetAllAssetPaths()
            where assetPath.StartsWith(t4MControlTextureHeader) || assetPath.StartsWith(postProcessTextureHeader)
            where EditorAssetConst.textureExtensions.Contains(Path.GetExtension(assetPath))
            select assetPath;
        foreach (var control in controls)
            hashSet.Add(control);
        return hashSet;
    }

    private static void SetIosCompression(TextureImporter importer, bool isCompress)
    {
        var platformSetting = importer.GetPlatformTextureSettings("iPhone");
        if (isCompress)
        {
            platformSetting.overridden = true;
            platformSetting.textureCompression = TextureImporterCompression.Compressed;
            platformSetting.crunchedCompression = true;
            var useRgba = importer.textureCompression.ToString().StartsWith("RGBA", StringComparison.OrdinalIgnoreCase);
            platformSetting.format = useRgba ? TextureImporterFormat.ETC2_RGBA8Crunched : TextureImporterFormat.ETC_RGB4Crunched;
        }
        else
            platformSetting.overridden = false;
    }
    
    [MenuItem("Bundle V2/Purge/Set All IPhone Textures")]
    public static void SetAllIPhoneTextures()
    {
        var importers = (from assetPath in AssetDatabase.GetAllAssetPaths()
            where assetPath.StartsWith(AssetConst.nonInternalHeader)
            where EditorAssetConst.textureExtensions.Contains(Path.GetExtension(assetPath))
            let importer = AssetImporter.GetAtPath(assetPath) as TextureImporter
            where importer
            select importer).ToArray();
        for (var i = 0; i < importers.Length; i++)
        {
            EditorUtility.DisplayProgressBar("配置苹果压缩格式",
                string.Format("{0} / {1}", i + 1, importers.Length),
                (float)i / importers.Length);
            var importer = importers[i];
            var platformSetting = importer.GetPlatformTextureSettings("iPhone");
            if (importer.textureCompression != TextureImporterCompression.Uncompressed &&
                importer.textureType == TextureImporterType.Sprite)
            {
                platformSetting.overridden = true;
                platformSetting.textureCompression = TextureImporterCompression.Compressed;
                platformSetting.crunchedCompression = true;
                platformSetting.format = TextureImporterFormat.ETC2_RGBA8Crunched;
            }
            else
            {
                platformSetting.overridden = false;
            }
            importer.SetPlatformTextureSettings(platformSetting);
            importer.SaveAndReimport();
        }
    }
    
    [MenuItem("Bundle V2/Purge/Texture Compress")]
    public static void PurgeCompression()
    {
        var nonCompress = GetNonCompressTextures();
        var allTextures = (from assetPath in AssetDatabase.GetAllAssetPaths()
            where assetPath.StartsWith("Assets/")
            where EditorAssetConst.textureExtensions.Contains(Path.GetExtension(assetPath))
            select assetPath).ToArray();
        for (var i = 0; i < allTextures.Length; i++)
        {
            var texture = allTextures[i];
            EditorUtility.DisplayProgressBar("Check Texture", string.Format("({0} / {1})", i, allTextures.Length),
                (float) i / allTextures.Length);
            var importer = AssetImporter.GetAtPath(texture) as TextureImporter;
            if (importer)
            {
                var dirty = false;
                var compress = nonCompress.Contains(texture)
                    ? TextureImporterCompression.Uncompressed
                    : TextureImporterCompression.Compressed;
                if (compress != importer.textureCompression)
                {
                    dirty = true;
                    importer.textureCompression = compress;
                    SetIosCompression(importer, compress != TextureImporterCompression.Uncompressed);
                }

                if (compress == TextureImporterCompression.Compressed && !importer.crunchedCompression)
                {
                    dirty = true;
                    importer.crunchedCompression = true;
                }

                if (importer.textureType == TextureImporterType.Sprite && importer.mipmapEnabled)
                {
                    dirty = true;
                    importer.mipmapEnabled = false;
                }

                if (dirty)
                    importer.SaveAndReimport();
            }
        }

        EditorUtility.ClearProgressBar();
    }

    private static string[] GetAllTexturePaths()
    {
        var assetPaths = from assetPath in AssetDatabase.GetAllAssetPaths()
            where EditorAssetConst.textureExtensions.Contains(Path.GetExtension(assetPath))
            select assetPath;
        return assetPaths.ToArray();
    }

    private class ReimportSpriteAction : EditorPerFrameActionBase
    {
        private readonly string[] _assetPaths;
        private int _index;

        public ReimportSpriteAction(string[] assetPaths)
        {
            _assetPaths = assetPaths;
        }

        protected override int GetTotalCount()
        {
            return _assetPaths.Length;
        }

        protected override int GetCurrentIndex()
        {
            return _index;
        }

        protected override void PerFrameAction()
        {
            var assetPath = _assetPaths[_index];
            var importer = AssetImporter.GetAtPath(assetPath) as TextureImporter;
            if (importer != null && importer.textureType == TextureImporterType.Sprite)
                importer.SaveAndReimport();
            _index++;
        }
    }

    private class GetAllNonPowerAction : EditorPerFrameActionBase
    {
        private const string _filePath = "Assets/_Test/NonPower2Textures.txt";
        private readonly string[] _assetPaths;
        private readonly StringBuilder _builder;
        private int _index;

        public GetAllNonPowerAction(string[] assetPaths)
        {
            _assetPaths = assetPaths;
            _builder = new StringBuilder();
        }

        protected override int GetTotalCount()
        {
            return _assetPaths.Length;
        }

        protected override int GetCurrentIndex()
        {
            return _index;
        }

        protected override void PerFrameAction()
        {
            var assetPath = _assetPaths[_index];
            var importer = AssetImporter.GetAtPath(assetPath) as TextureImporter;
            if (importer != null && importer.textureType != TextureImporterType.Sprite)
            {
                var args = new object[2];
                var mi = typeof(TextureImporter).GetMethod("GetWidthAndHeight",
                    BindingFlags.NonPublic | BindingFlags.Instance);
                if (mi != null)
                    mi.Invoke(importer, args);
                if (args[0] == null || args[1] == null)
                {
                    Debug.LogError("无法获得贴图尺寸,于" + importer.assetPath);
                    _builder.AppendLine(importer.assetPath + "; 尺寸无法获得!");
                }
                else
                {
                    var width = (int) args[0];
                    var height = (int) args[1];
                    if (!IsPowerOf2(width) || !IsPowerOf2(height))
                        _builder.AppendLine(importer.assetPath +
                                            string.Format("; 尺寸 {0} x {1} 不是2的次方!", width, height));
                }
            }

            _index++;
        }

        protected override void OnFinish()
        {
            base.OnFinish();
            var filePath = Application.dataPath.MoveUp().Open(_filePath);
            File.WriteAllText(filePath, _builder.ToString());
            Debug.LogWarning("贴图尺寸扫描结果已输出到 " + filePath);
        }

        private static bool IsPowerOf2(int number)
        {
            // 如果小于等于1
            if (number < 2) return false;

            // 或者二进制中1的位数超过1位,即不是二的次方
            int count;
            for (count = 0; count < number; count++)
                number &= number - 1; // 清除最低位的1
            return count < 2;
        }
    }
}