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

namespace Managers
{
    using Costumes;
    using Employees;
    using Offers;
    using System;
    using Saver;
    using UnityEngine.Events;

    [Serializable]
    public class GameData
    {
        public string logoID = "";
        public string agencyName;
        public int budget;
        public int rating;

        public DateTime currentTime;
        public DateTime gameStartTime;

        public List<OfferData> offers = new List<OfferData>();
        public List<EmployeeData> employees = new List<EmployeeData>();
        public List<CostumeData> costumes = new List<CostumeData>();

        public int offerSpawnerID = 1;

        public int earnedMoney = 0;
    }

    public class DataManager : Utils.SingletonComponent<DataManager>
    {
        [SerializeField] private LogoConfig logoDB;
        [SerializeField] private bool saveOnChange = true;

        private Sprite logo;

        private GameData data = null;

        public int Budget
        {
            get => data.budget;
            set
            {
                data.budget = value;
                onBudgetChanged?.Invoke(value);

                if (data.budget <= 0)
                    GameManager.Instance.GameOver();

                if (saveOnChange)
                    onDataUpdate?.Invoke(data);
            }
        }

        public int EarnedMoney
        {
            get => data.earnedMoney;
            set
            {
                data.earnedMoney = value;

                if (saveOnChange)
                    onDataUpdate?.Invoke(data);
            }
        }

        public int Rating
        {
            get => data.rating;
            set
            {
                data.rating = value;
                onRateChanged?.Invoke(value);

                if (saveOnChange)
                    onDataUpdate?.Invoke(data);
            }
        }

        public string AgencyName
        {
            get => data.agencyName;
            set
            {
                data.agencyName = value;

                if (saveOnChange)
                    onDataUpdate?.Invoke(data);
            }
        }

        public DateTime CurrentTime
        {
            get => data.currentTime;
            set
            {
                data.currentTime = value;

                if (saveOnChange)
                    onDataUpdate?.Invoke(data);
            }
        }

        public DateTime GameStartTime
        {
            get => data.gameStartTime;
            set
            {
                data.gameStartTime = value;

                if (saveOnChange)
                    onDataUpdate?.Invoke(data);
            }
        }

        public List<OfferData> Offers
        {
            get => data.offers;
            set
            {
                data.offers = value;

                if (saveOnChange)
                    onDataUpdate?.Invoke(data);
            }
        }

        public List<CostumeData> Costumes
        {
            get => data.costumes;
            set
            {
                data.costumes = value;

                if (saveOnChange)
                    onDataUpdate?.Invoke(data);
            }
        }

        public List<EmployeeData> Employees
        {
            get => data.employees;
            set
            {
                data.employees = value;

                if (saveOnChange)
                    onDataUpdate?.Invoke(data);
            }
        }

        public int OfferSpawnerID
        {
            get => data.offerSpawnerID;
            set
            {
                data.offerSpawnerID = value;

                if (saveOnChange)
                    onDataUpdate?.Invoke(data);
            }
        }

        public Sprite Logo => logo;

        public bool HasAccount => data.logoID != "";

        private UnityEvent<GameData> onDataUpdate = new UnityEvent<GameData>();
        private UnityEvent<int> onBudgetChanged = new UnityEvent<int>();
        private UnityEvent<int> onRateChanged = new UnityEvent<int>();

        private UnityEvent onDataLoaded = new UnityEvent();

        private bool isLoaded = false;

        private void Awake()
        {
            DontDestroyOnLoad(this);
            onDataUpdate.AddListener(SaveManager.Save);
            onDataUpdate.AddListener((data) => Debug.Log("Saved"));
        }

        void Start()
        {
            data = SaveManager.Load();
            if (data.logoID != "")
                logo = logoDB.logos.Find(x => x.id == data.logoID)?.icon;

            isLoaded = true;
            onDataLoaded?.Invoke();
        }

        public void Save() => SaveManager.Save(data);

        public void Init(string logoID, string agencyName, int budget, int rating, List<CostumeData> costumes, List<EmployeeData> employees)
        {
            data = new GameData();
            data.logoID = logoID;
            data.agencyName = agencyName;
            data.budget = budget;
            data.rating = rating;
            data.costumes = costumes;
            data.employees = employees;

            logo = logoDB.logos.Find(x => x.id == data.logoID)?.icon;

            Save();
        }

        public void InitTime(DateTime currentTime, DateTime gameStartTime)
        {
            data.currentTime = currentTime;
            data.gameStartTime = gameStartTime;

            Save();
        }

        public void ResetProgress()
        {
            onDataLoaded = new UnityEvent();
            onDataUpdate = new UnityEvent<GameData>();
            onRateChanged = new UnityEvent<int>();
            onBudgetChanged = new UnityEvent<int>();

            SaveManager.ResetProgress();

            data = new GameData();
        }

        public void SubscribeOnBudgetChange(UnityAction<int> callback) => onBudgetChanged.AddListener(callback);
        public void SubscribeOnRateChange(UnityAction<int> callback) => onRateChanged.AddListener(callback);
        public void SubscribeOnLoad(UnityAction callback)
        {
            if (isLoaded)
            {
                callback?.Invoke();
                return;
            }

            onDataLoaded.AddListener(callback);
        }
    }
}