using System;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;

namespace CatsUdonTools.Editor
{
    /// <summary>
    /// 複製済みマテリアルが参照するテクスチャを入稿フォルダへコピーし、マテリアルの参照をコピー側へ差し替える。
    /// エディタ時のみ動作し、プレイヤービルドには含まれない。入稿者の元テクスチャ・.meta は変更しない
    /// </summary>
    internal static class SubmissionTextureDuplicator
    {
        private const string AssetsPrefix = "Assets/";
        private const string PackagesPrefix = "Packages/";

        /// <summary>
        /// materials が参照する Assets・Packages 配下のテクスチャを texturesFolder へコピーして差し替える
        /// </summary>
        public static void ReplaceWithCopies(IEnumerable<Material> materials, string texturesFolder)
        {
            // 同じ元テクスチャを複数マテリアルが共有していても、コピーは 1 回だけにするため
            var copiedByOriginal = new Dictionary<Texture, Texture>();

            foreach (var material in materials)
            {
                ReplaceMaterialTextures(material, texturesFolder, copiedByOriginal);
                EditorUtility.SetDirty(material);
            }
        }

        private static void ReplaceMaterialTextures(Material material, string texturesFolder, Dictionary<Texture, Texture> copiedByOriginal)
        {
            foreach (var propertyName in material.GetTexturePropertyNames())
            {
                var original = material.GetTexture(propertyName);
                if (original == null)
                {
                    continue;
                }

                var copy = GetOrCreateCopy(original, texturesFolder, copiedByOriginal);
                if (copy != original)
                {
                    material.SetTexture(propertyName, copy);
                }
            }
        }

        private static Texture GetOrCreateCopy(Texture original, string texturesFolder, Dictionary<Texture, Texture> copiedByOriginal)
        {
            if (copiedByOriginal.TryGetValue(original, out var existingCopy))
            {
                return existingCopy;
            }

            var copy = CopyTextureAsset(original, texturesFolder);
            copiedByOriginal.Add(original, copy);
            return copy;
        }

        private static Texture CopyTextureAsset(Texture original, string texturesFolder)
        {
            var originalPath = AssetDatabase.GetAssetPath(original);
            if (!IsCopyableTextureFile(original, originalPath))
            {
                return original;
            }

            var copyPath = AssetDatabase.GenerateUniqueAssetPath($"{texturesFolder}/{Path.GetFileName(originalPath)}");
            AssetDatabase.CopyAsset(originalPath, copyPath);
            AssetDatabase.ImportAsset(copyPath);
            return AssetDatabase.LoadAssetAtPath<Texture>(copyPath);
        }

        // Packages/ の画像（VCC で入れた Poiyomi の MatCap など）もコピーする。変換サーバーに同じパッケージがあるとは限らず、
        // 入稿物に入っていないと真っ白になるため（2026-10-12、Poiyomi の MatCap を使った lilToon の球が白くなった）。
        // ビルトイン・RenderTexture はコピーできない／する意味がない。
        // FBX 内蔵テクスチャなどのサブアセットは CopyAsset すると親ファイルごと複製されるため除外する
        private static bool IsCopyableTextureFile(Texture texture, string assetPath)
        {
            if (!assetPath.StartsWith(AssetsPrefix, StringComparison.Ordinal) && !assetPath.StartsWith(PackagesPrefix, StringComparison.Ordinal))
            {
                return false;
            }

            // Packages/ はパッケージキャッシュ上の実ファイルを指す仮想パスなので、実際の場所で確かめる
            return AssetDatabase.IsMainAsset(texture) && File.Exists(FileUtil.GetPhysicalPath(assetPath));
        }
    }
}
