using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using KCM.StateManagement.Observers;
using static KCM.Main;

namespace KCM.Packets.Lobby
{
    public class SaveTransferPacket : Packet
    {
        public override ushort packetId => (ushort)Enums.Packets.SaveTransferPacket;

        public static byte[] saveData = new byte[1];
        public static bool[] chunksReceived = new bool[1];
        public static bool loadingSave = false;
        public static int received = 0;

        public static void ResetTransferState()
        {
            loadingSave = false;
            received = 0;
            saveData = new byte[1];
            chunksReceived = new bool[1];
        }


        public int chunkId { get; set; }
        public int chunkSize { get; set; }

        public int saveSize { get; set; }
        public int saveDataIndex { get; set; }
        public int totalChunks { get; set; }

        public byte[] saveDataChunk { get; set; }

        public override void HandlePacketClient()
        {
            bool initialisingTransfer = !loadingSave ||
                                       saveData == null ||
                                       saveData.Length != saveSize ||
                                       chunksReceived == null ||
                                       chunksReceived.Length != totalChunks;

            if (initialisingTransfer)
            {
                Main.helper.Log("Save Transfer started!");
                loadingSave = true;
                received = 0;

                StateObserver.ClearAll();

                saveData = new byte[saveSize];
                chunksReceived = new bool[totalChunks];

                if (ServerLobbyScript.LoadingSave != null)
                    ServerLobbyScript.LoadingSave.SetActive(true);
            }

            if (chunkId < 0 || chunkId >= totalChunks)
            {
                Main.helper.Log($"Invalid save chunk id: {chunkId} / {totalChunks}");
                return;
            }

            if (saveDataChunk == null)
            {
                Main.helper.Log($"Null save chunk data for chunk: {chunkId}");
                return;
            }

            if (saveDataIndex < 0 || saveDataIndex + saveDataChunk.Length > saveData.Length)
            {
                Main.helper.Log($"Invalid save chunk write range: index={saveDataIndex} len={saveDataChunk.Length} size={saveData.Length}");
                return;
            }

            Array.Copy(saveDataChunk, 0, saveData, saveDataIndex, saveDataChunk.Length);
            chunksReceived[chunkId] = true;
            received += chunkSize;

            float savePercent = saveSize > 0 ? (float)received / (float)saveSize : 0f;
            if (ServerLobbyScript.ProgressBar != null)
                ServerLobbyScript.ProgressBar.fillAmount = savePercent;
            if (ServerLobbyScript.ProgressBarText != null)
                ServerLobbyScript.ProgressBarText.text = (savePercent * 100).ToString("0.00") + "%";
            if (ServerLobbyScript.ProgressText != null)
                ServerLobbyScript.ProgressText.text = $"{((float)(received / 1000)).ToString("0.00")} KB / {((float)(saveSize / 1000)).ToString("0.00")} KB";


            if (chunkId + 1 == totalChunks)
            {
                Main.helper.Log($"Received last save transfer packet.");

                Main.helper.Log(WhichIsNotComplete());
            }

            // Check if all chunks have been received
            if (IsTransferComplete())
            {
                // Handle completed transfer here
                Main.helper.Log("Save Transfer complete!");

                LoadSaveLoadHook.saveBytes = saveData;
                LoadSaveLoadHook.memoryStreamHook = true;

                LoadSave.Load();


                LoadSaveLoadHook.saveContainer.Unpack(null);
                Broadcast.OnLoadedEvent.Broadcast(new OnLoadedEvent());

                try
                {
                    new KCM.Packets.Network.ResyncRequestPacket { reason = "post-load" }.Send();
                }
                catch
                {
                }

                if (ServerLobbyScript.LoadingSave != null)
                    ServerLobbyScript.LoadingSave.SetActive(false);

                loadingSave = false;
                received = 0;
                saveData = new byte[1];
                chunksReceived = new bool[1];
            }
        }

        public static bool IsTransferComplete()
        {
            return chunksReceived.All(x => x == true);
        }

        public static string WhichIsNotComplete()
        {
            string notComplete = "";
            for (int i = 0; i < chunksReceived.Length; i++)
            {
                if (!chunksReceived[i])
                {
                    notComplete += i + ", ";
                }
            }
            return notComplete;
        }

        public override void HandlePacketServer()
        {
        }
    }
}
