using System;
using UnityEngine;

namespace UVC.Core
{

    #region Singleton

    /// <summary>
    /// MonoBehaviour가 아닌 일반 클래스를 위한 싱글톤 패턴
    /// 지연 초기화(lazy initialization)를 사용하여 필요할 때만 인스턴스 생성
    /// </summary>
    /// <typeparam name="T">싱글톤으로 구현할 클래스 타입(반드시 기본 생성자가 있어야 함)</typeparam>
    /// <example>
    /// <code>
    /// public class JournalClass
    /// {
    ///     // 클래스 내용
    /// }
    /// 
    /// // 싱글톤 사용 예시
    /// var journalSingleton = Singleton<JournalClass>.Instance;
    /// </code>
    /// </example>
    public class Singleton<T> where T : class, new()
    {
        /// <summary>
        /// 싱글톤 인스턴스를 지연 초기화 방식으로 생성
        /// </summary>
        protected static readonly Lazy<T> instance = new Lazy<T>(() => new T());

        /// <summary>
        /// 외부에서 생성자 직접 호출 방지
        /// </summary>
        protected Singleton(){}

        /// <summary>
        /// 싱글톤 인스턴스에 접근하기 위한 전역 접근점
        /// </summary>
        /// <example>
        /// <code>
        /// // 싱글톤 인스턴스 접근 방법
        /// MyClass instance = Singleton<MyClass>.Instance;
        /// </code>
        /// </example>
        public static T Instance { get { return instance.Value; } }
    }
    #endregion


    #region SingletonApp

    /// <summary>
    /// 씬 전환 시에도 유지되는 MonoBehaviour 기반 싱글톤
    /// DontDestroyOnLoad를 통해 씬 전환 시에도 객체가 파괴되지 않음
    /// </summary>
    /// <typeparam name="T">MonoBehaviour를 상속받는 컴포넌트 타입</typeparam>
    /// <example>
    /// <code>
    /// // 사용 예시
    /// public class AppMain : SingletonApp<AppMain>
    /// {
    ///     protected override void Init()
    ///     {
    ///         // 초기화 코드 작성
    ///         ULog.Debug("AppMain 초기화 완료");
    ///     }
    /// }
    /// 
    /// // 접근 방법
    /// AppMain.Instance.SomeMethod();
    /// </code>
    /// </example>
    public abstract class SingletonApp<T> : UnityEngine.MonoBehaviour where T : UnityEngine.Component
    {
        /// <summary>
        /// 싱글톤 인스턴스
        /// </summary>
        private static T instance;

        /// <summary>
        /// 싱글톤 인스턴스에 접근하기 위한 전역 접근점
        /// 인스턴스가 없는 경우 자동으로 생성함
        /// </summary>
        /// <example>
        /// <code>
        /// // 접근 방법
        /// MyAppSingleton.Instance.DoSomething();
        /// </code>
        /// </example>
        public static T Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = (T)GameObject.FindFirstObjectByType(typeof(T)); // Updated to use FindFirstObjectByType
                    if (instance == null)
                    {
                        // 씬에 인스턴스가 없으면 새로 생성
                        instance = new GameObject(string.Format(typeof(T) + "")).AddComponent<T>();
                    }
                }
                return instance;
            }
        }

        /// <summary>
        /// 컴포넌트가 활성화될 때 호출되는 Unity 메소드
        /// 인스턴스 설정 및 씬 전환 시 객체 유지 설정
        /// </summary>
        protected virtual void Awake()
        {
            if (instance == null)
            {
                instance = this as T;
            }
            // 인스턴스 초기화 호출
            (instance as SingletonApp<T>).Init();
            //if (transform.parent != null && transform.root != null)
            //{
            //    DontDestroyOnLoad(transform.root.gameObject);
            //}
            //else
            {
                // 씬 전환 시에도 파괴되지 않도록 설정
                DontDestroyOnLoad(gameObject);
            }
        }

        /// <summary>
        /// 인스턴스화될 때 호출되는 초기화 메소드
        /// 자식 클래스에서 오버라이드하여 초기화 로직 구현
        /// </summary>
        /// <example>
        /// <code>
        /// protected override void Init()
        /// {
        ///     // 초기화 코드 작성
        ///     playerData = new PlayerData();
        ///     LoadSettings();
        /// }
        /// </code>
        /// </example>
        protected virtual void Init() { }

    }
    #endregion

    #region SingletonScene

    /// <summary>
    /// 현재 씬 내에서만 유지되는 MonoBehaviour 기반 싱글톤
    /// 씬 전환 시 인스턴스가 파괴됨
    /// </summary>
    /// <typeparam name="T">MonoBehaviour를 상속받는 컴포넌트 타입</typeparam>
    /// <example>
    /// <code>
    /// // 사용 예시
    /// public class SceneMain : SingletonScene<SceneMain>
    /// {
    ///     protected override void Init()
    ///     {
    ///         // 초기화 코드 작성
    ///         ULog.Debug("SceneMain 초기화 완료");
    ///     }
    /// }
    /// 
    /// // 접근 방법
    /// SceneMain.Instance.SomeMethod();
    /// </code>
    /// </example>
    public abstract class SingletonScene<T> : UnityEngine.MonoBehaviour where T : UnityEngine.Component
    {
        /// <summary>
        /// 싱글톤 인스턴스
        /// </summary>
        private static T instance;

        /// <summary>
        /// 싱글톤 인스턴스에 접근하기 위한 전역 접근점
        /// 인스턴스가 없는 경우 자동으로 생성함
        /// </summary>
        /// <example>
        /// <code>
        /// // 접근 방법
        /// MySceneSingleton.Instance.DoSomething();
        /// </code>
        /// </example>
        public static T Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = (T)GameObject.FindFirstObjectByType(typeof(T)); // Updated to use FindFirstObjectByType
                    if (instance == null)
                    {
                        // 씬에 인스턴스가 없으면 새로 생성
                        instance = new GameObject(string.Format(typeof(T) + "")).AddComponent<T>();
                    }
                }
                return instance;
            }
        }


        /// <summary>
        /// 컴포넌트가 활성화될 때 호출되는 Unity 메소드
        /// 인스턴스 설정 및 초기화
        /// </summary>
        protected virtual void Awake()
        {
            if (instance == null)
            {
                instance = this as T;
                
            }
            // 인스턴스 초기화 호출
            (instance as SingletonScene<T>).Init();
        }

        /// <summary>
        /// 인스턴스화될 때 호출되는 초기화 메소드
        /// 자식 클래스에서 오버라이드하여 초기화 로직 구현
        /// </summary>
        /// <example>
        /// <code>
        /// protected override void Init()
        /// {
        ///     // 초기화 코드 작성
        ///     uiManager = GetComponent<UIManager>();
        ///     SetupEventListeners();
        /// }
        /// </code>
        /// </example>
        protected virtual void Init() { }

        /// <summary>
        /// 컴포넌트가 파괴될 때 호출되는 Unity 메소드
        /// 싱글톤 인스턴스 참조 해제
        /// </summary>
        protected virtual void OnDestroy()
        {
            instance = null;
        }

    }
    #endregion
}