using UnityEngine;
using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.IO;
using Util;

namespace CM3D2.MultipleMaids.Plugin
{
    public partial class MultipleMaids
    {
        private static readonly byte[] pngEnd = Encoding.ASCII.GetBytes("IEND");
        private static string sceneData;
        private const string baseDirectoryName = "< Base Directory >";
        private string saveScenePath = Path.Combine(Path.GetFullPath(".\\"), "Mod\\MultipleMaidsSave");
        private List<SavePng> saveScenes = new List<SavePng>(50);
        private string[] directoryList;
        private Texture2D frame;
        private Rect saveManagerRect;
        private Rect saveModalRect;
        private Rect resizeManagerRect;
        private Vector2 saveManagerScrollPos = Vector2.zero;
        private Vector2 dirListScrollPos = Vector2.zero;
        private bool saveManagerInitialize = false;
        private bool loadSaveFlag = false;
        private bool overwriteFlag = false;
        private bool createSaveFlag = false;
        private bool manageSaveFlag = false;
        private bool createDirectory = false;
        private bool resizeManager = false;
        private int selectedSave = 0;
        private int selectedDirectory = 0;
        private string currentDirectory = "";
        private string textFieldValue = "";

        public void InitializeSaveManager()
        {
            frame = MakeTex(2, 2, Color.white);

            if (!Directory.Exists(saveScenePath))
            {
                Directory.CreateDirectory(saveScenePath);
            }

            GetSaveDirectories();
            InitializeSaveList();
            saveManagerInitialize = true;
        }
        private void RefreshSaveManager()
        {
            SwitchDirectory(currentDirectory);
            GetSaveDirectories();
            InitializeSaveList();
        }

        private void InitializeSaveList()
        {
            saveScenes.Clear();

            string workingPath = Path.Combine(saveScenePath, currentDirectory);

            DirectoryInfo info = new DirectoryInfo(workingPath);

            foreach (var save in info.GetFiles("*.png"))
            {
                Texture2D screenshot = new Texture2D(1, 1, TextureFormat.ARGB32, false);
                screenshot.LoadImage(File.ReadAllBytes(save.FullName));

                saveScenes.Add(new SavePng(save, screenshot));
            }

            selectedSave = saveScenes.Count == 0 ? 0 : saveScenes.Count - 1;

            saveScenes.Sort((a, b) => a.info.LastWriteTime.CompareTo(b.info.LastWriteTime));
            saveManagerScrollPos.y = 0;
        }

        private void GetSaveDirectories()
        {
            DirectoryInfo[] directoryInfo = new DirectoryInfo(saveScenePath).GetDirectories();
            directoryList = new string[directoryInfo.Length + 1];
            directoryList[0] = baseDirectoryName;

            for (int i = 0; i < directoryInfo.Length; i++)
            {
                directoryList[i + 1] = directoryInfo[i].Name;
            }
        }

        private void SwitchDirectory(string target)
        {
            if (target.Equals(baseDirectoryName)) target = "";

            string targetDirectory = Path.Combine(saveScenePath, target);

            if (!Directory.Exists(targetDirectory))
            {
                currentDirectory = "";
                selectedDirectory = 0;
                GetSaveDirectories();
            }
            else
            {
                selectedDirectory = Array.FindIndex(directoryList, d => d.Equals(target, StringComparison.OrdinalIgnoreCase));
                selectedDirectory = selectedDirectory == -1 ? 0 : selectedDirectory;

                if (target == currentDirectory) return;

                currentDirectory = target;
            }
            InitializeSaveList();
        }

        private void LoadSave()
        {
            string filePath = saveScenes[selectedSave].info.FullName;
            if (!File.Exists(filePath))
            {
                InitializeSaveList();
                sceneData = null;
                return;
            }

            using (FileStream fileStream = File.OpenRead(filePath))
            {
                byte[] buffer = new byte[pngEnd.Length];
                long position = 0;

                while (true)
                {
                    int bytesRead = fileStream.Read(buffer, 0, buffer.Length);

                    if (bytesRead != pngEnd.Length)
                    {
                        sceneData = null;
                        return;
                    }

                    if (BytesEqual(buffer, pngEnd))
                    {
                        fileStream.Position += 4;
                        break;
                    }

                    fileStream.Position = ++position;
                }
                using (MemoryStream sceneStream = LZMA.Decompress(fileStream))
                {
                    sceneData = Encoding.Unicode.GetString(sceneStream.ToArray());
                }
            }
            SavePng temp = saveScenes[selectedSave];
            saveScenes.RemoveAt(selectedSave);
            saveScenes.Add(temp);
            saveManagerScrollPos.y = 0;
        }

        private void Overwrite()
        {
            string filePath = saveScenes[selectedSave].info.FullName;
            if (!File.Exists(filePath))
            {
                RefreshSaveManager();
            }
            else
            {
                File.Delete(filePath);
                saveScenes.RemoveAt(selectedSave);
                saveManagerScrollPos.y = 0;
            }
        }

        private void MakeNewDirectory(string directoryName)
        {
            directoryName = string.Join("", directoryName.Split(Path.GetInvalidFileNameChars()));
            string newDirectory = Path.Combine(saveScenePath, directoryName);
            if (!Directory.Exists(newDirectory))
            {
                Directory.CreateDirectory(newDirectory);
            }
            GetSaveDirectories();
            SwitchDirectory(directoryName);
        }

        private void SaveScene()
        {
            string saveDirectory = Path.Combine(saveScenePath, currentDirectory);

            if (!Directory.Exists(saveDirectory))
            {

                thum_byte_to_base64_ = "";
                thum_file_path_ = "";
                RefreshSaveManager();
                return;
            }

            string sceneString = SerializeScene(true);

            #region MM GUI stuff

            Texture2D screenshot = new Texture2D(1, 1, TextureFormat.ARGB32, false);
            screenshot.LoadImage(File.ReadAllBytes(thum_file_path_));
            float num2 = screenshot.width / (float)screenshot.height;
            Vector2 vector2 = new Vector2(480f, 270f);
            int newWidth = screenshot.width;
            int newHeight = screenshot.height;
            if (vector2.x < (double)screenshot.width && vector2.y < (double)screenshot.height)
            {
                newWidth = (int)vector2.x;
                newHeight = Mathf.RoundToInt(newWidth / num2);
                if (vector2.y < (double)newHeight)
                {
                    newHeight = (int)vector2.y;
                    newWidth = Mathf.RoundToInt(newHeight * num2);
                }
            }
            else if (vector2.x < (double)screenshot.width)
            {
                newWidth = (int)vector2.x;
                newHeight = Mathf.RoundToInt(newWidth / num2);
            }
            else if (vector2.y < (double)screenshot.height)
            {
                newHeight = (int)vector2.y;
                newWidth = Mathf.RoundToInt(newHeight * num2);
            }
            TextureScale.Bilinear(screenshot, newWidth, newHeight);
            #endregion

            thum_byte_to_base64_ = "";
            thum_file_path_ = "";

            string filePath = Path.Combine(saveDirectory, $"mmsave{DateTime.Now:yyyyMMddHHmmss}.png");
            using (FileStream fileStream = File.Create(filePath))
            using (MemoryStream sceneStream = new MemoryStream(Encoding.Unicode.GetBytes(sceneString)))
            {
                byte[] screenshotBuffer = screenshot.EncodeToPNG();
                byte[] sceneBuffer = LZMA.Compress(sceneStream);
                fileStream.Write(screenshotBuffer, 0, screenshotBuffer.Length);
                fileStream.Write(sceneBuffer, 0, sceneBuffer.Length);
            }
            saveScenes.Add(new SavePng(new FileInfo(filePath), screenshot));
            selectedSave = saveScenes.Count - 1;
        }

        private static bool BytesEqual(byte[] a, byte[] b)
        {
            if (a.Length != b.Length) return false;

            for (int i = 0; i < a.Length; i++)
            {
                if (a[i] != b[i]) return false;
            }
            return true;
        }
        class SavePng
        {
            public FileInfo info { get; }
            public Texture2D screenshot { get; }
            public SavePng(FileInfo info, Texture2D screenshot)
            {
                this.info = info;
                this.screenshot = screenshot;
            }
        }
    }
}
