/**
 * @file    ExternalDependencyEditor.cs
 * 
 * @author  disker
 * @date    2020-present
 * @copyright Copyright © Com2uS Platform Corporation. All Right Reserved.
 * @defgroup Hive.Unity.Editor
 * @{
 * @brief HIVE External Dependency EditorWindow <br/><br/>
 */

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

namespace Hive.Unity.Editor
{
    using ExternalDependencyDictionary = Dictionary<ExternalDependencyType, bool>;
    using ExternalDependencySerializableDictionary = SerializableDictionary<string, bool>;

    public class ExternalDependencyEditor : EditorWindow
    {
        // UI Control
        private static bool needToCloseWithoutPopup = true;
        private static bool checkChangedUI = false;

        // Layout Option
        
        // Hive Dependencies UI 초기 크기
        private static int editorWidth = 460;       // 디자인을 고려해 임의 설정함
        private static Vector2 editorInitPosition = new Vector2(800, 0);
        private static int questionBtnMargin = 25;
        private GUILayoutOption[] labelOption = {GUILayout.Width(220), GUILayout.ExpandWidth(false)}; 

        private GUILayoutOption[] labelOSTargetWidth = {GUILayout.Width(20), GUILayout.ExpandWidth(false)}; 
        private GUILayoutOption[] toggleWidth = {GUILayout.Width(60),GUILayout.ExpandWidth(false)};

        private GUILayoutOption[] helpBtnOption = {GUILayout.Width(20),GUILayout.ExpandWidth(false)};
        private GUILayoutOption[] filterOption = {GUILayout.Width(180),GUILayout.ExpandWidth(false)};
        private GUILayoutOption[] titleLabelOptions = {GUILayout.Width(135), GUILayout.Height(50), GUILayout.ExpandWidth(true)};
        private GUILayoutOption[] commentLabelOptions = {GUILayout.Width(135), GUILayout.Height(35), GUILayout.ExpandWidth(true)};
        private GUILayoutOption[] editorMainBtnOption = {GUILayout.Height(35)};

        
        [SerializeField]
        private Vector2 scrollPos = Vector2.zero;

        private static ExternalDependencyDictionary androidDependency;
        private static ExternalDependencyDictionary iosDependency;

        // Help Url 
        private const string developerPageHelpUrl = "https://developers.hiveplatform.ai/";
        private const string hiveConfigurationHelpUrl = "https://developers.hiveplatform.ai/ko/latest/dev/overview/features/unity-features/#externaldependency_1";
        private const string idpHelpUrl = "https://developers.hiveplatform.ai/ko/latest/dev/authv4/#v4-idplist";
        private const string iapHelpUrl = "https://developers.hiveplatform.ai/ko/latest/dev/billing/#supported-features";
        private const string pushHelpUrl = "https://developers.hiveplatform.ai/ko/latest/dev/notification/";
        private const string analyticsHelpUrl = "https://developers.hiveplatform.ai/ko/latest/dev/analytics/";

        // OptionGroup
        private bool showGroupHiveModule = true;
        private bool showGroupIdp = true;
        private bool showGroupMarket = true;
        private bool showGroupAnalytics = true;
        private bool showGroupPush = true;

        // Hive Module (Label)
        private static GUIContent hivePromotionLabel = new GUIContent("Promotion", "Promotion 사용 여부 설정 (true, false)");
        private static GUIContent googleInAppReviewLabel = new GUIContent("  └─ Google InAppReview", "Google InAppReview 사용 여부 설정 (true, false)");
        private static GUIContent hiveDeviceManagementLabel = new GUIContent("Device Management", "Device Management 사용 여부 설정 (true, false)");
        private static GUIContent hivePealNameVerificationLabel = new GUIContent("Real Name Verification", "Real Name Verification 사용 여부 설정 (true, false)");
        private static GUIContent herculesLabel = new GUIContent("Hercules", "Hercules 사용 여부 설정 (true, false)");
        private static GUIContent recaptchaLabel = new GUIContent("reCAPTCHA", "reCAPTCHA 사용 여부 설정 (true, false)");
        private static GUIContent dataStoreLabel = new GUIContent("DataStore", "DataStore 사용 여부 설정 (true, false)");
        private static GUIContent googleInAppUpdateLabel = new GUIContent("Google InAppUpdate", "Google InAppUpdate 사용 여부 설정 (true, false)");
        private static GUIContent analyticsConsentModeLabel = new GUIContent("Analytics Consent-Mode", "Analytics Consent-Mode 사용 여부 설정 (true, false)");
        private static GUIContent matchMakingLabel = new GUIContent("Match Making", "Match Making 사용 여부 설정 (true, false)");
        private static GUIContent chatLabel = new GUIContent("Chat", "Chat 사용 여부 설정 (true, false)");
        private static GUIContent hiveAdultConfirmLabel = new GUIContent("Adult Confirm", "Adult Confirm 사용 여부 설정 (true, false)");

        // Auth (Label)
        private static GUIContent googleSignInLabel = new GUIContent("Google SignIn", "Google SignIn 사용 여부 설정 (true, false)");
        private static GUIContent googlePlayGamesLabel = new GUIContent("Google Play Games", "Google Play Games 사용 여부 설정 (true, false)");
        private static GUIContent facebookLabel = new GUIContent("Facebook", "Facebook 사용 여부 설정 (true, false)");
        private static GUIContent appleGameCenterLabel = new GUIContent("Apple GameCenter", "Apple GameCenter 사용 여부 설정 (true, false)");
        private static GUIContent appleSignInLabel = new GUIContent("Apple SignIn", "Apple SignIn 사용 여부 설정 (true, false)");
        private static GUIContent lineLabel = new GUIContent("Line", "Line 사용 여부 설정 (true, false)");
        private static GUIContent vkLabel = new GUIContent("VK", "VK 사용 여부 설정 (true, false)");
        private static GUIContent qqLabel = new GUIContent("QQ", "QQ 사용 여부 설정 (true, false)");
        private static GUIContent wechaLabel = new GUIContent("Wechat", "Wechat 사용 여부 설정 (true, false)");
        private static GUIContent weverseLabel = new GUIContent("Weverse", "Weverse 사용 여부 설정 (true, false)");
        private static GUIContent hiveMembershipLabel = new GUIContent("Hive Membership", "Hive Membership 사용 여부 설정 (true, false)");
        private static GUIContent hiveGuestLabel = new GUIContent("Hive Guest", "Hive Guest 사용 여부 설정 (true, false)");
        private static GUIContent xLabel = new GUIContent("X", "X 사용 여부 설정 (true, false)");
        private static GUIContent steamLabel = new GUIContent("Steam", "Steam 사용 여부 설정 (true, false)");
        private static GUIContent telegramLabel = new GUIContent("Telegram", "Telegram 사용 여부 설정 (true, false)");
        private static GUIContent huaweiLabel = new GUIContent("Huawei", "Huawei 사용 여부 설정 (true, false)");

        // Push (Label)
        private static GUIContent pushGoogleFcmLabel = new GUIContent("Google FCM", "Google FCM 사용 여부 설정 (true, false)");
        private static GUIContent pushAppleLabel = new GUIContent("Apple APNs", "Apple APNs 사용 여부 설정 (included)");
        private static GUIContent pushAmazonADMLabel = new GUIContent("Amazon ADM", "Amazon ADM 사용 여부 설정 (true, false)");

        // Market (Label)
        private static GUIContent androidMarketGoogleLabel = new GUIContent("Google PlayStore", "Google PlayStore 사용 여부 설정 (true, false)");
        private static GUIContent iOSMarketAppleLabel = new GUIContent("Apple AppStore", "Apple AppStore 사용 여부 설정 (true, false)");
        private static GUIContent androidMarketOneStoreLabel = new GUIContent("OneStore", "OneStore 사용 여부 설정 (true, false)");
        private static GUIContent androidMarketAmazonLabel = new GUIContent("Amazon AppStore", "Amazon AppStore 사용 여부 설정 (true, false)");
        private static GUIContent androidMarketLebiLabel = new GUIContent("Lebi", "Lebi 사용 여부 설정 (true, false)");
        private static GUIContent androidMarketHiveStoreLabel = new GUIContent("Hive Store", "Hive Store 사용 여부 설정 (true, false)");
        private static GUIContent androidMarketSamsungLabel = new GUIContent("Samsung GalaxyStore", "Samsung GalaxyStore 사용 여부 설정 (true, false)");
        private static GUIContent androidMarketHuaweiLabel = new GUIContent("Huawei AppGallery", "Huawei AppGallery 사용 여부 설정 (true, false)");

        // Analytics (Label)
        private static GUIContent adjustLabel = new GUIContent("Adjust", "Adjust 사용 여부 설정 (true, false)");
        private static GUIContent airbridgeLabel = new GUIContent("Airbridge", "Airbridge 사용 여부 설정 (true, false)");
        private static GUIContent appsFlyerLabel = new GUIContent("AppsFlyer", "AppsFlyer 사용 여부 설정 (true, false)");
        private static GUIContent singularLabel = new GUIContent("Singular", "Singular 사용 여부 설정 (true, false)");
        private static GUIContent firebaseLabel = new GUIContent("Firebase", "Firebase 사용 여부 설정 (true, false)");


        [MenuItem("Hive/Hive Dependencies (ExternalDependency)")]
        public static void create()
        {
            var projectWindow = EditorWindow.GetWindow(Type.GetType("UnityEditor.ProjectBrowser,UnityEditor"));
            // 현재 열려있는 Unity 프로젝트창 위치 획득 후 기준값에 open
            if(projectWindow != null)
            {
                Rect projectWindowRect = projectWindow.position;
                editorInitPosition = new Vector2(projectWindowRect.x + 800, projectWindowRect.y);       // Hive Config editor 가로 길이만큼 우측 이후에 표시
            }
            create(true, editorInitPosition);
        }

        // 디펜던시 세이브 파일 사용 여부, 지난 닫기 시 위치 정보를 활용하여 노출
        public static void create(bool useLocalSaveFile, Vector2 lastPosition)
        {
            var editor = (ExternalDependencyEditor)EditorWindow.GetWindow(typeof(ExternalDependencyEditor), true, "Hive Dependencies");
            editor.Initialize(useLocalSaveFile, lastPosition);
            editor.Show();
        }

        public void Initialize(bool useLocalSaveFile, Vector2 lastPosition)
        {
            this.minSize = new Vector2(editorWidth, editorWidth * 2);        // width를 기준으로 높이는 2배로 임의 설정
            this.maxSize = new Vector2(editorWidth * 2, float.MaxValue);
            this.position = new Rect(lastPosition, minSize);    // 새로 UI 시작 시 지정위치
 
            // UI를 새로 노출하는 경우
            if(useLocalSaveFile)
            {
                initDependenciesState();     // 임시 저장 변수 초기화

                androidDependency = ExternalDependencyDictionaryManager.LoadExternalDependencyDictionary(ExternalDependencyDictionaryManager.SupportOSType.Android);
                iosDependency = ExternalDependencyDictionaryManager.LoadExternalDependencyDictionary(ExternalDependencyDictionaryManager.SupportOSType.iOS);
                // 로컬 세이브 파일의 정보를 임시 변수에도 동기화
                ExternalDependencyDictionaryManager.setTempDependencies(androidDependency, ExternalDependencyDictionaryManager.SupportOSType.Android);
                ExternalDependencyDictionaryManager.setTempDependencies(iosDependency, ExternalDependencyDictionaryManager.SupportOSType.iOS);
            }   
        }

        public static bool isShowing()
        {
            if(EditorWindow.HasOpenInstances<ExternalDependencyEditor>())
            {
                return true;
            }
            return false;
        }

        void DrawUILine(Color color, int thickness = 1, int padding = 10)
        {
            Rect r = EditorGUILayout.GetControlRect(GUILayout.Height(padding+thickness));
            r.height = thickness;
            r.y+=padding/2;
            r.x-=2;
            r.width +=6;
            EditorGUI.DrawRect(r, color);
        }

        GUIStyle getEditorTitleStyle()
        {
            GUIStyle titleStyle = new GUIStyle();
            titleStyle.fontSize = 30;
            titleStyle.normal.textColor = Color.white;
            return titleStyle;
        }

        GUIStyle getFolderTextStyle()
        {
            GUIStyle folderStyle = new GUIStyle(EditorStyles.foldout);
            folderStyle.normal.textColor = Color.white;
            folderStyle.alignment = TextAnchor.MiddleLeft;
            return folderStyle;
        }

        GUIStyle getTextStyle(ExternalDependencyDictionaryManager.SupportOSType osType)
        {
            // ios or android
            GUIStyle osStyle = new GUIStyle();
            if(osType == ExternalDependencyDictionaryManager.SupportOSType.iOS)
            {
                osStyle.normal.textColor = Color.cyan;
            }
            else if(osType == ExternalDependencyDictionaryManager.SupportOSType.Android)
            {
                osStyle.normal.textColor = Color.green;
            }
            
            osStyle.alignment = TextAnchor.MiddleLeft;
            return osStyle;
        }

        GUIStyle getQuestionBtnStyle()
        {
            GUIStyle btnStyle = EditorStyles.miniButton;
            btnStyle.alignment = TextAnchor.MiddleCenter;
            btnStyle.normal.textColor = Color.gray;
            return btnStyle;
        }

        float getFloatFromtoggle(bool value) {
            if(value)
                return 1f;
            else
                return 0;
        }

        // UI가 오픈된 상태에서 코드변경 감지 시 OnGUI가 재호출됩니다.
        // 이때 클래스 내 객체가 null이 되는 요소는 초기값을 반영해주어야
        // 열려있는 UI가 미노출되는 이슈를 대응할 수 있습니다.
        private void prepareOnGUI()
        {
            // Unity 프로젝트 변경사항 감지로 다시 OnGUI 될때 변수에 있던 Dependency 값이 null이 되므로
            // 값을 다시 임시 변수 기준으로 갱신.
            // (다시 OnGUI 될 때 Hive Dependencies 창이 닫히는 이슈 수정)
            if(androidDependency == null)
            {
                androidDependency = ExternalDependencyDictionaryManager.getTempDependencies(ExternalDependencyDictionaryManager.SupportOSType.Android);
                if(androidDependency == null)
                {
                    // 임시 변수에도 값이 없는 경우 로컬 세이브 파일 정보 사용
                    // (예 : Hive Dependencies 창을 열고 다른 작업하여 Unity 프로젝트 갱신될 때 임수 변수도 초기화됨)
                    androidDependency = ExternalDependencyDictionaryManager.LoadExternalDependencyDictionary(ExternalDependencyDictionaryManager.SupportOSType.Android);
                }
            }
            if(iosDependency == null)
            {
                iosDependency = ExternalDependencyDictionaryManager.getTempDependencies(ExternalDependencyDictionaryManager.SupportOSType.iOS);
                if(iosDependency == null)
                {
                    // 임시 변수에도 값이 없는 경우 로컬 세이브 파일 정보 사용
                    // (예 : Hive Dependencies 창을 열고 다른 작업하여 Unity 프로젝트 갱신될 때 임수 변수도 초기화됨)
                    iosDependency = ExternalDependencyDictionaryManager.LoadExternalDependencyDictionary(ExternalDependencyDictionaryManager.SupportOSType.iOS);
                }
            }
        }

        // 새 EditorWindow가 생성될 떄 호출됩니다.
        // OnGUI() 에서 사용되는 객체 중 null 여부를 확인하여 null인 경우 값을 할당해야하는 경우 OnEnable() 에서 진행합니다.
        private void OnEnable()
        {
            prepareOnGUI();
        }

        void OnGUI()
        {
            // draw title area
            EditorGUILayout.BeginVertical();
            {
                EditorGUILayout.BeginHorizontal();
                GUILayout.Space(20);
                EditorGUILayout.LabelField("Hive Dependencies", getEditorTitleStyle(), titleLabelOptions);
                EditorGUILayout.EndHorizontal();

                EditorGUILayout.BeginHorizontal();
                GUILayout.Space(20);
                EditorGUILayout.LabelField("\'Hive Dependencies\' settings are supported independently for each OS.\n(Hive Dependenices 설정은 각 OS별로 독립적으로 지원합니다.)\n", commentLabelOptions);
                EditorGUILayout.EndHorizontal();

                DrawUILine(Color.grey);     // 구분선

                EditorGUILayout.BeginHorizontal();
                GUILayout.Space(270); // 좌측 여백
                EditorGUILayout.LabelField("Android", getTextStyle(ExternalDependencyDictionaryManager.SupportOSType.Android), labelOSTargetWidth);
                GUILayout.Space(55); // 좌측 여백
                EditorGUILayout.LabelField("iOS", getTextStyle(ExternalDependencyDictionaryManager.SupportOSType.iOS), labelOSTargetWidth);
                EditorGUILayout.EndHorizontal();
            }
            GUILayout.Space(10);
            EditorGUILayout.EndVertical();

            // draw contenta area
            try {
                EditorGUI.BeginChangeCheck();   // UI 변경사항 감지

                scrollPos = EditorGUILayout.BeginScrollView(scrollPos);
                {
                    // Hive Module
                    EditorGUILayout.BeginVertical();
                    EditorGUI.indentLevel++;
                    EditorGUILayout.EndVertical();

                    EditorGUILayout.BeginVertical();
                    {
                        this.showGroupHiveModule = EditorGUILayout.Foldout(this.showGroupHiveModule, "Hive Module Settings", getFolderTextStyle());
                        if(this.showGroupHiveModule)
                        {
                            EditorGUI.indentLevel++;

                            // HivePromotion
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(hiveConfigurationHelpUrl, hivePromotionLabel);
                            setOSDependenciesToggle(ExternalDependencyType.HivePromotion, 0);
                            if(!androidDependency[ExternalDependencyType.HivePromotion])
                            {
                                androidDependency[ExternalDependencyType.GoogleInAppReview] = false;
                            }
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // GoogleInAppReview
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(hiveConfigurationHelpUrl, googleInAppReviewLabel);
                            setOSDependenciesToggle(ExternalDependencyType.GoogleInAppReview, 1);
                            if(androidDependency[ExternalDependencyType.GoogleInAppReview])
                            {
                                androidDependency[ExternalDependencyType.HivePromotion] = true;
                            }

                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // HiveDeviceManagement
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(hiveConfigurationHelpUrl, hiveDeviceManagementLabel);
                            setOSDependenciesToggle(ExternalDependencyType.HiveDeviceManagement, 0);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // HiveRealNameVerification
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(hiveConfigurationHelpUrl, hivePealNameVerificationLabel);
                            setOSDependenciesToggle(ExternalDependencyType.HiveRealNameVerification, 0);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // Hercules
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(hiveConfigurationHelpUrl, herculesLabel);
                            setOSDependenciesToggle(ExternalDependencyType.Hercules, 0);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // Recaptcha
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(hiveConfigurationHelpUrl, recaptchaLabel);
                            setOSDependenciesToggle(ExternalDependencyType.Recaptcha, 0);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // HiveAdultConfirm
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(hiveConfigurationHelpUrl, hiveAdultConfirmLabel);
                            setOSDependenciesToggle(ExternalDependencyType.HiveAdultConfirm, 0);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // DataStore
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(hiveConfigurationHelpUrl, dataStoreLabel);
                            setOSDependenciesToggle(ExternalDependencyType.DataStore, 0);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // GoogleInAppUpdate
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(hiveConfigurationHelpUrl, googleInAppUpdateLabel);
                            setOSDependenciesToggle(ExternalDependencyType.GoogleInAppUpdate, 1);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // AnalyticsConsentMode
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(hiveConfigurationHelpUrl, analyticsConsentModeLabel);
                            setOSDependenciesToggle(ExternalDependencyType.AnalyticsConsentMode, 0);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // MatchMaking
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(hiveConfigurationHelpUrl, matchMakingLabel);
                            setOSDependenciesToggle(ExternalDependencyType.MatchMaking, 0);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // Chat
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(hiveConfigurationHelpUrl, chatLabel);
                            setOSDependenciesToggle(ExternalDependencyType.Chat, 0);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            EditorGUI.indentLevel--;               
                        }
                        EditorGUI.indentLevel--;
                    }
                    EditorGUILayout.EndVertical();

                    DrawUILine(Color.grey);

                    // Idp
                    EditorGUILayout.BeginVertical();
                    EditorGUI.indentLevel++;
                    EditorGUILayout.EndVertical();

                    EditorGUILayout.BeginVertical();
                    {
                        this.showGroupIdp = EditorGUILayout.Foldout(this.showGroupIdp, "Auth Settings");
                        if(this.showGroupIdp)
                        {
                            EditorGUI.indentLevel++;

                            // HiveMembership
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(idpHelpUrl, hiveMembershipLabel);
                            setOSDependenciesToggle(ExternalDependencyType.HiveMembership, 0);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // Google SignIn
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(idpHelpUrl, googleSignInLabel);
                            setOSDependenciesToggle(ExternalDependencyType.Google, 0);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // Google PlayGames
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(idpHelpUrl, googlePlayGamesLabel);
                            setOSDependenciesToggle(ExternalDependencyType.GooglePlayGames, 1);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // Facebook
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(idpHelpUrl, facebookLabel);
                            setOSDependenciesToggle(ExternalDependencyType.Facebook, 0);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // Apple GameCenter
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(idpHelpUrl, appleGameCenterLabel);
                            EditorGUILayout.LabelField("", toggleWidth);        // 간격 조정을 위한 빈 labelField 추가
                            setOSDependenciesToggle(ExternalDependencyType.Apple, 2);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // Apple SignIn
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(idpHelpUrl, appleSignInLabel);
                            setOSDependenciesToggle(ExternalDependencyType.AppleSignIn, 0);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // Line
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(idpHelpUrl, lineLabel);
                            setOSDependenciesToggle(ExternalDependencyType.Line, 0);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // VK
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(idpHelpUrl, vkLabel);
                            setOSDependenciesToggle(ExternalDependencyType.VK, 0);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // QQ
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(idpHelpUrl, qqLabel);
                            setOSDependenciesToggle(ExternalDependencyType.QQ, 0);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // Wechat
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(idpHelpUrl, wechaLabel);
                            setOSDependenciesToggle(ExternalDependencyType.Wechat, 0);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // Weverse
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(idpHelpUrl, weverseLabel);
                            setOSDependenciesToggle(ExternalDependencyType.Weverse, 0);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // Steam
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(idpHelpUrl, steamLabel);
                            setOSDependenciesToggle(ExternalDependencyType.Steam, 0);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // X
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(idpHelpUrl, xLabel);
                            setOSDependenciesToggle(ExternalDependencyType.X, 0);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // Telegram
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(idpHelpUrl, telegramLabel);
                            setOSDependenciesToggle(ExternalDependencyType.Telegram, 0);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // setDefaultMarkWithLabel(hiveGuestLabel, idpHelpUrl);    // default 셋팅 예

                            // Huawei (Global)
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(idpHelpUrl, huaweiLabel);
                            setOSDependenciesToggle(ExternalDependencyType.Huawei, 1);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();
                            // about Huawei agconnect-services
                            if(EditorGUILayout.BeginFadeGroup(getFloatFromtoggle(androidDependency[ExternalDependencyType.Huawei])))
                            {
                                EditorGUI.indentLevel++;
                                EditorGUILayout.BeginHorizontal();
                                EditorGUILayout.LabelField("(Huawei) Add the 'agconnect-services.json' to your app.", commentLabelOptions);
                                EditorGUILayout.EndHorizontal();
                                EditorGUI.indentLevel--;
                            }
                            else {
                                // nothing to do 
                            }
                            EditorGUILayout.EndFadeGroup();

                            EditorGUI.indentLevel--;
                        }
                        EditorGUI.indentLevel--;
                    }
                    EditorGUILayout.EndVertical();

                    DrawUILine(Color.grey);

                    // Push
                    EditorGUILayout.BeginVertical();
                    EditorGUI.indentLevel++;
                    EditorGUILayout.EndVertical();

                    EditorGUILayout.BeginVertical();
                    {
                        this.showGroupPush = EditorGUILayout.Foldout(this.showGroupPush, "Push Settings");
                        if(this.showGroupPush)
                        {
                            EditorGUI.indentLevel++;

                            // Google FCM
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(pushHelpUrl, pushGoogleFcmLabel);
                            setOSDependenciesToggle(ExternalDependencyType.PushGoogleFcm, 1);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // Apple APNs
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(pushHelpUrl, pushAppleLabel);
                            EditorGUILayout.LabelField("", toggleWidth);        // 간격 조정을 위한 빈 labelField 추가
                            EditorGUI.BeginDisabledGroup(true);
                            if(File.Exists(ExternalDependencyConst.editorPath + "/ExternalDependency/iOS/iOSDependencyInfo.cs")) {
                                bool appleAPNsValue = EditorGUILayout.Toggle(true, toggleWidth);
                            } else {
                                bool appleAPNsValue = EditorGUILayout.Toggle(false, toggleWidth);
                            }
                            EditorGUI.EndDisabledGroup();
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // Amazon ADM
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(pushHelpUrl, pushAmazonADMLabel);
                            setOSDependenciesToggle(ExternalDependencyType.PushAmazonAdm, 1);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            EditorGUI.indentLevel--;
                        }
                        EditorGUI.indentLevel--;
                    }
                    EditorGUILayout.EndVertical();

                    DrawUILine(Color.grey);

                    // Market
                    EditorGUILayout.BeginVertical();
                    EditorGUI.indentLevel++;
                    EditorGUILayout.EndVertical();

                    EditorGUILayout.BeginVertical();
                    {
                        this.showGroupMarket = EditorGUILayout.Foldout(this.showGroupMarket, "Market Settings");
                        if(this.showGroupMarket)
                        {
                            EditorGUI.indentLevel++;

                            // Google PlayStore
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(iapHelpUrl, androidMarketGoogleLabel);
                            setOSDependenciesToggle(ExternalDependencyType.MarketGoogle, 1);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // Apple AppStore
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(iapHelpUrl, iOSMarketAppleLabel);
                            EditorGUILayout.LabelField("", toggleWidth);        // 간격 조정을 위한 빈 labelField 추가
                            setOSDependenciesToggle(ExternalDependencyType.MarketApple, 2);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // OneStore
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(iapHelpUrl, androidMarketOneStoreLabel);
                            setOSDependenciesToggle(ExternalDependencyType.MarketOneStore, 1);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // Amazon AppStore
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(iapHelpUrl, androidMarketAmazonLabel);
                            setOSDependenciesToggle(ExternalDependencyType.MarketAmazon, 1);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // Lebi
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(iapHelpUrl, androidMarketLebiLabel);
                            setOSDependenciesToggle(ExternalDependencyType.MarketLebi, 1);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // Hive Store
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(iapHelpUrl, androidMarketHiveStoreLabel);
                            setOSDependenciesToggle(ExternalDependencyType.MarketHiveStore, 1);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // Samsung GalaxyStore
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(iapHelpUrl, androidMarketSamsungLabel);
                            setOSDependenciesToggle(ExternalDependencyType.MarketSamsung, 1);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // Huawei AppGallery
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(iapHelpUrl, androidMarketHuaweiLabel);
                            setOSDependenciesToggle(ExternalDependencyType.MarketHuawei, 1);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            EditorGUI.indentLevel--;
                        }
                        EditorGUI.indentLevel--;
                    }
                    EditorGUILayout.EndVertical();

                    DrawUILine(Color.grey);

                    // Analytics
                    EditorGUILayout.BeginVertical();
                    EditorGUI.indentLevel++;
                    EditorGUILayout.EndVertical();

                    EditorGUILayout.BeginVertical();
                    {
                        this.showGroupAnalytics = EditorGUILayout.Foldout(this.showGroupAnalytics, "Analytics Settings");
                        if(this.showGroupAnalytics)
                        {
                            EditorGUI.indentLevel++;

                            // Adjust
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(analyticsHelpUrl, adjustLabel);
                            setOSDependenciesToggle(ExternalDependencyType.Adjust, 0);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // Airbridge
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(analyticsHelpUrl, airbridgeLabel);
                            setOSDependenciesToggle(ExternalDependencyType.Airbridge, 0);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // AppsFlyer
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(analyticsHelpUrl, appsFlyerLabel);
                            setOSDependenciesToggle(ExternalDependencyType.AppsFlyer, 0);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // Singular
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(analyticsHelpUrl, singularLabel);
                            setOSDependenciesToggle(ExternalDependencyType.Singular, 0);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();

                            // Firebase
                            EditorGUILayout.BeginHorizontal();
                            setModuleLabel(analyticsHelpUrl, firebaseLabel);
                            setOSDependenciesToggle(ExternalDependencyType.Firebase, 0);
                            EditorGUI.indentLevel++;
                            EditorGUILayout.EndHorizontal();
                            // about Firebase google-services
                            if(EditorGUILayout.BeginFadeGroup(getFloatFromtoggle(androidDependency[ExternalDependencyType.Firebase])))
                            {
                                EditorGUI.indentLevel++;
                                EditorGUILayout.BeginHorizontal();
                                EditorGUILayout.LabelField("(Firebase) Add the 'google-services.json' to your app.", commentLabelOptions);
                                EditorGUILayout.EndHorizontal();
                                EditorGUI.indentLevel--;
                            }
                            else {
                                // nothing to do 
                            }
                            EditorGUILayout.EndFadeGroup();

                            EditorGUI.indentLevel--;
                        }
                        EditorGUI.indentLevel--;
                        GUILayout.Space(20);
                    }
                    EditorGUILayout.EndVertical();
                }
                // Scroll 영역 종료
                EditorGUILayout.EndScrollView();

                // UI 변경사항을 감지
                // - 체크박스를 임의 제어한 경우 모두 감지됨
                // - 체크박스를 원래 값으로 되돌려놓아도 감지됨
                if (EditorGUI.EndChangeCheck())
                {
                    taskForUIChagned();
                }

                /*
                 * Buttons area
                 */
                EditorGUILayout.BeginVertical();

                // OK button
                bool okButton = GUILayout.Button("Save", editorMainBtnOption);

                // Reset to Defaults button
                if (GUILayout.Button("Reset", editorMainBtnOption))
                {
                    ExternalDependencyDictionaryManager.Reset(ExternalDependencyDictionaryManager.SupportOSType.Android, ref androidDependency);
                    ExternalDependencyDictionaryManager.Reset(ExternalDependencyDictionaryManager.SupportOSType.iOS, ref iosDependency);

                    taskForUIChagned();
                }

                // Close button
                bool closeButton = GUILayout.Button("Close", editorMainBtnOption);   
                
                // OK button event (Save)
                if (okButton)
                {
                    HiveLogger.Log(String.Format("Save (HiveSDK Dependencies)"));
                    initDependenciesState();

                    // (1) HiveSDK 종합 xml 파일(/Editor/HiveSDKSettingsDependencies.xml)을 구성
                    // (더이상 provider 별 **Dependencies.xml)을 사용하지 않습니다!)                
                    Dictionary<ExternalDependencyDictionaryManager.SupportOSType, Dictionary<ExternalDependencyType, bool>> osDependency = new Dictionary<ExternalDependencyDictionaryManager.SupportOSType, Dictionary<ExternalDependencyType, bool>>();
                    osDependency[ExternalDependencyDictionaryManager.SupportOSType.Android] = androidDependency;
                    osDependency[ExternalDependencyDictionaryManager.SupportOSType.iOS] = iosDependency;
                    ExternalDependencyDictionaryManager.createHiveSDKSettingsDependenciesXmlFile(osDependency);
                    // 임시 설정 배포 파일인 TempHiveSDKSettingsDependenciex.xml이 있다면 제거 (ExternalDependencyLoader 동작이 이루어지기 전 삭제)
                    ExternalDependencyUtil.deleteFile(ExternalDependencyConst.hiveDependenciesTempXmlPath);

                    // 디펜던시에 따른 외부 라이브러리 파일을 import 제외
                    ExternalDependencyDictionaryManager.SetupIncludedExternalDependency(ExternalDependencyDictionaryManager.SupportOSType.Android, androidDependency);
                    ExternalDependencyDictionaryManager.SetupIncludedExternalDependency(ExternalDependencyDictionaryManager.SupportOSType.iOS, androidDependency);

                    // (2) 세이브 파일 구성 (/ProjectSettings/HiveDependencies.xml)
                    ExternalDependencyDictionaryManager.SaveExternalDependencyDictionary(androidDependency, iosDependency);
                    AssetDatabase.Refresh();

                    ExternalDependencyDictionaryManager.ResolveEDM4U();

                    // Save 버튼 플로우 마지막에 완료 팝업 노출
                    if (EditorUtility.DisplayDialog("Hive Dependencies", "Setup and save complete.\n설정 및 저장 완료.", "OK"))
                    {
                        HiveLogger.Log("OK button clicked.");
                    }
                }
                // Close button event
                if (closeButton) Close(true);

                EditorGUILayout.EndVertical();

            } catch (Exception ex) {
                // Exception 발생 시 강제 닫기 처리
                checkChangedUI = false;
                Close(true);   
                HiveLogger.Log("Hive Dependencies OnGUI exception : " + ex);
            }
        }

        private void taskForUIChagned()
        {
            HiveLogger.Log("Hive Dependencies UI option changed.");
            checkChangedUI = true;
                    
            // 임시 변수에 저장
            // - OnGUI 갱신이 될 경우 변수 값을 기준으로 갱신
            ExternalDependencyDictionaryManager.setTempDependencies(androidDependency, ExternalDependencyDictionaryManager.SupportOSType.Android);
            ExternalDependencyDictionaryManager.setTempDependencies(iosDependency, ExternalDependencyDictionaryManager.SupportOSType.Android);
        }

        // lifecyle(override)
        private void Close(bool forcedClose)
        {
            if(forcedClose)
            {
                needToCloseWithoutPopup = true;
            }
            else
            {
                needToCloseWithoutPopup = false;
            }
            base.Close();
        }

        // lifecyle(override)
        private void OnDestroy()
        {
            HiveLogger.Log("Hive Dependencies OnDestroy");

            // UI 변경사항이 있거나 forced close를 원하지 않는 경우 >> 닫기 전 안내 팝업 노출
            if(checkChangedUI == true || needToCloseWithoutPopup == false)
            {
                // Editor 닫을 시 팝업으로 안내
                if (EditorUtility.DisplayDialog("Hive Dependencies", "The option UI has changed.\nAre you sure you want to close this window?\n옵션 변경사항이 있었습니다.\n저장하지 않고 창을 닫습니다.", "Yes", "No"))
                {
                    // 'YES'
                    HiveLogger.Log("Hive Dependencies UI closed.");
                    checkChangedUI = false;
                }
                else
                {
                    // 'NO'

                    // 팝업을 통해 취소했더라도 Unity는 이미 창을 닫는 처리를 진행했기 때문에 여기서 창을 다시 열어야 함
                    HiveLogger.Log("Hive Dependencies UI reopen.");
                    Vector2 lastWindowPosition = position.position; // 창을 닫지 않길 원하는 경우 제자리에 reopen하기 위한 위치 확인

                    EditorApplication.delayCall += () =>
                    {
                        create(false, lastWindowPosition);  // 로컬 세이브 파일 사용하지 않고 UI 오픈
                    };
                }
            }
        }

        // 임시 저장한 디펜던시 정보를 초기화, 팝업의 닫기 시 안내 정보를 초기화
        private void initDependenciesState()
        {
            ExternalDependencyDictionaryManager.initTempDependencies();
            needToCloseWithoutPopup = true;
            checkChangedUI = false;
        }

        // 디펜던시 라벨 및 안내 문구 제어
        private void setModuleLabel(string helpUrl, GUIContent moduleLabel) {
            GUILayout.Space(questionBtnMargin);
            if(GUILayout.Button("?", getQuestionBtnStyle(), helpBtnOption)) {
                Application.OpenURL(helpUrl);
            }
            EditorGUI.indentLevel--;
            EditorGUILayout.LabelField(moduleLabel, labelOption);
        }

        // 디펜던시에 대해서 OS별 체크박스 그리기 제어
        private void setOSDependenciesToggle(ExternalDependencyType type, int supportOSIndex) {

            bool existAndroidUnityComponent = false;
            bool existIosUnityComponent = false;
            if(File.Exists(ExternalDependencyConst.editorPath + "/ExternalDependency/Android/AndroidDependencyInfo.cs")) {
                existAndroidUnityComponent = true;
            }
            if(File.Exists(ExternalDependencyConst.editorPath + "/ExternalDependency/iOS/iOSDependencyInfo.cs")) {
                existIosUnityComponent = true;
            }

            // supportOSIndex : 0~2
            // - 0 : Android, iOS
            // - 1 : Android
            // - 2 : iOS
            switch(supportOSIndex) {
                case 0 : {

                    if(existAndroidUnityComponent) {
                        androidDependency[type] = EditorGUILayout.Toggle(androidDependency[type], toggleWidth);
                    } else {
                        // AndroidDependencyInfo 파일 부재 시 비활성 처리
                        EditorGUI.BeginDisabledGroup(true);
                        androidDependency[type] = false;
                        androidDependency[type] = EditorGUILayout.Toggle(androidDependency[type], toggleWidth);
                        EditorGUI.EndDisabledGroup();
                    }
                    if(existIosUnityComponent) {
                        iosDependency[type] = EditorGUILayout.Toggle(iosDependency[type], toggleWidth);
                    } else {
                        // iOSDependencyInfo 파일 부재 시 비활성 처리
                        EditorGUI.BeginDisabledGroup(true);
                        iosDependency[type] = false;
                        iosDependency[type] = EditorGUILayout.Toggle(iosDependency[type], toggleWidth);
                        EditorGUI.EndDisabledGroup();
                    }
                    break;
                }
                case 1 : {

                    if(existAndroidUnityComponent) {
                        androidDependency[type] = EditorGUILayout.Toggle(androidDependency[type], toggleWidth);
                    } else {
                        // AndroidDependencyInfo 파일 부재 시 비활성 처리
                        EditorGUI.BeginDisabledGroup(true);
                        androidDependency[type] = false;
                        androidDependency[type] = EditorGUILayout.Toggle(androidDependency[type], toggleWidth);
                        EditorGUI.EndDisabledGroup();
                    }
                    iosDependency[type] = false;
                    break;
                }
                case 2 : {
                    androidDependency[type] = false;
                    if(existIosUnityComponent) {
                        iosDependency[type] = EditorGUILayout.Toggle(iosDependency[type], toggleWidth);
                    } else {
                        // iOSDependencyInfo 파일 부재 시 비활성 처리
                        EditorGUI.BeginDisabledGroup(true);
                        iosDependency[type] = false;
                        iosDependency[type] = EditorGUILayout.Toggle(iosDependency[type], toggleWidth);
                        EditorGUI.EndDisabledGroup();
                    }
                    break;
                }
                default : {
                    break;
                }
            }
        }
    }
}