using System;
using System.Collections.Generic;
using UnityEngine;

public abstract class SceneBaseDataManager<T> : MonoBehaviour
{
    protected virtual string OBJECT_FOLDER_NAME => "";
    protected virtual string OBJECT_LIST_NAME => "";


    protected UIBaseManager<T> UiManager;

    protected DataListManager<T> DynamicDataList;

    protected SceneBaseDataLoader<T> DataLoader { get; set; }

    public static SceneBaseDataManager<T> Instance; // { get; private set; }

    public virtual void Awake()
    {
        if (Instance == null)
        {
            Debug.Log("Create: "+gameObject);

            Instance = this;
        }
        else
        {
            Debug.Log(Instance);
            Debug.LogError(gameObject);
            Destroy(gameObject);
        }
    }

    /// <summary>
    /// Function to manage objects on scene depending on class responsibility
    /// 
    /// Important - USE THIS METHOD IN EVERY CHILD'S 'start' FUNCTION 
    /// </summary>
    public virtual void Start()
    {
        // Decide which element use during game
        AfterStart();
    }

    protected static SceneBaseDataManager<T> GetObjectType()
    {
        return GameObject.FindObjectOfType<SceneBaseDataManager<T>>();
    }

    /*    
     *    TODO WHAT WITH THAT...
     *    protected static SceneBaseDataManager<T> CreateInstance()
        {
            var managerGameObject = HandleManagerOnScene();

            if (!managerGameObject)
                throw new Exception("Game object to srote Managers scripts not found on scene!!!");

            return managerGameObject.AddComponent<SceneBaseDataManager<T>>();
        }

        /// <summary>
        /// Function to handel GLOBAL manager object from scene
        /// </summary>
        /// <returns></returns>
        protected static GameObject HandleManagerOnScene()
        {
            return GameObject.FindGameObjectWithTag("Manager").transform.Find("DataManger").gameObject;
        }*/

    /// <summary>
    /// Function to decide which data should be used
    /// 
    /// In common case it may sense and is correctly BUT
    /// In every UiPanel we want opposite:
    ///  - EquipmentDataManager
    ///  - SceneInventoryDataManager
    ///  - SceneTaskDataManager
    /// </summary>
    protected virtual void AfterStart()
    {
        if (OnMapAppearanceMethod.IsNewGameJustLaunched())
        {
            UseDefaultSettings();
        } else {
            UseDynamicSettings();
        }
    }

    protected abstract void UseDefaultSettings();
    protected abstract void UseDynamicSettings();

    #region Lad & Save
    protected virtual bool LoadData(SceneElementTypeEnum type, ref DataListManager<T> dataListManager)
    {        
        try 
        {
            dataListManager.SetList(
                DataLoader.LoadData(type) as List<T>
            );
            
            return true;
        }
        catch (Exception e) {
            Debug.LogWarning(e.Message);
        }

        return false;
    }

    protected virtual bool SaveData(List<T> _elements, SceneElementTypeEnum type)
    {
        try
        {
            DataLoader.SaveData(_elements, type);

            return true;
        }
        catch (Exception e) {
            Debug.LogError(e.Message);
        }

        return false;
    }
    #endregion

    #region DynamicData Methods
        /// <summary>
        /// Part of dynamic list CURD methods
        /// </summary>
    public bool LoadDynamicData()
    {
        return LoadData(SceneElementTypeEnum.Dynamic, ref DynamicDataList);
    }

    protected virtual void AddElementToDynamicList(T _element)
    {
        DynamicDataList.AddElementToList(_element);
    }

    protected virtual void RemoveElementFromDynamicList(T _element)
    {
        DynamicDataList.RemoveElementFromList(_element);
    }
    
    public virtual bool SaveDynamicData()
    {
        // TODO 
        // how to get list
        // 1. List in UI manager should be synchronized with list in this manager
        DynamicDataList.SetList(UiManager.GetList());

        // approach:
        // 1. get from outside, update local list && us it
        // 2. Handle list synchronized all the time & pass local list
        return SaveData(DynamicDataList.GetList(), SceneElementTypeEnum.Dynamic);
    }
    #endregion
}