using System;
using System.Collections.Generic;
using System.IO;
using JetBrains.Annotations;
using JohnsonUtils.Common;
using UnityEngine;
using UnityEngine.Events;

namespace JohnsonUtils.SaveSystem
{
    public class SaveManager : Singleton<SaveManager>
    {
        [UsedImplicitly]
        public static UnityAction<GameData> OnLoadCompleted;
        
        private static readonly List<ISaveData> SaveDataList = new ();

        private GameData _saveGame;
        private int _loadedGameNumber = -1;

        protected override void Awake()
        {
            base.Awake();
            _saveGame = new GameData();
        }

        private void Start() => Load();

        public void Save(int saveNumber = 1)
        {
            foreach (ISaveData saveData in SaveDataList)
            {
                saveData.Save(ref _saveGame);
            }
            
            string json = JsonUtility.ToJson(_saveGame);
            byte[] plainTextBytes = System.Text.Encoding.UTF8.GetBytes(json);
            string b64 = Convert.ToBase64String(plainTextBytes);
            using StreamWriter sw = new ($"saveData{saveNumber:00}.sgd");
            sw.Write(b64);
            _loadedGameNumber = -1;
        }

        public void SaveExplicit()
        {
            foreach (ISaveData saveData in SaveDataList)
            {
                saveData.Save(ref _saveGame);
            }
            string json = JsonUtility.ToJson(_saveGame);
            using StreamWriter sw = new ($"saveData01.json");
            sw.Write(json);
        }

        public void Load(int saveNumber = 1)
        {
            if (saveNumber != _loadedGameNumber)
            {
                try
                {
                    using StreamReader sr = new ($"saveData{saveNumber:00}.sgd");
                    string b64 = sr.ReadToEnd();
                    byte[] plainTextBytes = Convert.FromBase64String(b64);
                    string json = System.Text.Encoding.UTF8.GetString(plainTextBytes);
                    _saveGame = JsonUtility.FromJson<GameData>(json);
                }
                catch (FileNotFoundException)
                {
                    Debug.LogWarning($"Tried to load saveData{saveNumber:00}.sgd but file doesn't exist");
                }
                _loadedGameNumber = saveNumber;
            }

            foreach (ISaveData saveData in SaveDataList)
            {
                saveData.Load(ref _saveGame);
            }
            
            OnLoadCompleted?.Invoke(_saveGame);
        }

        [PublicAPI]
        public static void Register(ISaveData saveData)
        {
            if (!SaveDataList.Contains(saveData))
            {
                SaveDataList.Add(saveData);
            }
        }
        
        [PublicAPI]
        public static void Unregister(ISaveData saveData)
        {
            SaveDataList.Remove(saveData);
        }

        protected override void OnDestroy()
        {
            base.OnDestroy();
            Save();
        }
    }
}
