using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;
using UnityEngine.SceneManagement;
using VitDeck.Language;

namespace VitDeck.Validator
{
    public class LightmapSizeLimitRule : BaseRule
    {
        private readonly int lightmapCountLimit;
        private readonly int lightmapResolutionLimit;

        public LightmapSizeLimitRule(string name, int lightmapCountLimit, int lightmapResolutionLimit) : base(name)
        {
            this.lightmapCountLimit = lightmapCountLimit;
            this.lightmapResolutionLimit = lightmapResolutionLimit;
        }

        protected override void Logic(ValidationTarget target)
        {
            var scenes = target.GetScenes();

            // 全てリアルタイムであればlightmapの検証は不要
            var staticRenderersCount = target.GetAllObjects()
                .Where(IsWrittenToLightmap)
                .SelectMany(obj => obj.GetComponents<Renderer>())
                .Count();

            if (staticRenderersCount == 0)
            {
                return;
            }

            foreach (var scene in scenes)
            {
                LogicForScene(scene);
            }

            if (IsLightMapAutoGenerated())
            {
                AddIssue(new Issue(
                    null,
                    IssueLevel.Error,
                    LocalizedMessage.Get("LightmapSizeLimitRule.MustLightmapBakingManually"),
                    LocalizedMessage.Get("LightmapSizeLimitRule.MustLightmapBakingManually.Solution")));
            }
        }

        private bool IsWrittenToLightmap(GameObject obj)
        {
            if (!obj.activeInHierarchy)
            {
                return false;
            }

            var objStaticFlags = GameObjectUtility.GetStaticEditorFlags(obj);
            if ((objStaticFlags & StaticEditorFlags.ContributeGI) != StaticEditorFlags.ContributeGI)
            {
                return false;
            }

            return true;
        }

        void LogicForScene(Scene scene)
        {
            var lightmaps = LightmapSettings.lightmaps;
            if (lightmaps.Length > lightmapCountLimit)
            {
                AddIssue(new Issue(
                    null,
                    IssueLevel.Error,
                    LocalizedMessage.Get("LightmapSizeLimitRule.Overuse", lightmapCountLimit, lightmaps.Length),
                    LocalizedMessage.Get("LightmapSizeLimitRule.Overuse.Solution")
                    ));
            }

            foreach (var lightmap in lightmaps)
            {
                var texture = lightmap.lightmapDir;
                if (texture == null)
                {
                    continue;
                }
                if (texture.width > lightmapResolutionLimit || texture.height > lightmapResolutionLimit)
                {
                    AddIssue(new Issue(
                        null,
                        IssueLevel.Error,
                        LocalizedMessage.Get("LightmapSizeLimitRule.Overresolution", lightmapResolutionLimit, texture.width, texture.height),
                        LocalizedMessage.Get("LightmapSizeLimitRule.Overresolution.Solution", lightmapResolutionLimit)));
                }
            }
        }

        static bool IsLightMapAutoGenerated()
        {
            var lightmapSettings = GetLighmapSettings();
            return lightmapSettings.FindProperty("m_GIWorkflowMode").intValue == 0;
        }

        static SerializedObject GetLighmapSettings()
        {
            var getLightmapSettingsMethod = typeof(LightmapEditorSettings)
                .GetMethod("GetLightmapSettings", BindingFlags.Static | BindingFlags.NonPublic);
            var lightmapSettings = getLightmapSettingsMethod.Invoke(null, null) as UnityEngine.Object;
            return new SerializedObject(lightmapSettings);
        }
    }
}