#if UNITY_EDITOR
using ConjureOS.MetadataWindow;
using System;
using System.IO;
using System.IO.Compression;
using UnityEditor;
using UnityEngine;

namespace ConjureOS.UploaderWindow
{
    public class ConjureArcadeUploadProcessor
    {
        private const string logConjureArcade = "Conjure Arcade: ";

        private const string GameFolder = "game\\";
        private const string MediasFolder = "medias\\";
        private const string TempFolder = "temp\\";
        private const string MetadataFileName = "metadata.txt";

        /// <summary>
        /// Build and upload the game to the web server.
        /// Must use valid Conjure Arcade metadata, or the process will fail.
        /// </summary>
        /// <param name="metadata">The Conjure Arcade metadata of the game</param>
        /// <param name="metadataValidator">The metadata validator</param>
        public void BuildAndUpload(ConjureArcadeMetadata metadata, ConjureArcadeMetadataValidator metadataValidator)
        {
            // Step 1: Validate metadata
            if (!metadataValidator.ValidateMetadata(metadata))
            {
                ShowErrorDialog(
                    "Some entries in the game metadata are incorrect. " +
                    "You must fix them in order to upload the game to the web server.");
                return;
            }


            // Step 2: Build game
            string fileName;            // Name of the executable file
            string fileExtension;       // Extension of the executable file
            string buildDirectoryPath;  // Path to the build directory
            string tempDirectoryPath;   // Path to the temp directory, located inside the build directory
            try
            {
                // Get current build settings
                BuildPlayerOptions buildPlayerOptions = new BuildPlayerOptions();
                buildPlayerOptions = BuildPlayerWindow.DefaultBuildMethods.GetBuildPlayerOptions(buildPlayerOptions);

                // Get file and directory data
                fileName = Path.GetFileNameWithoutExtension(buildPlayerOptions.locationPathName);
                fileExtension = Path.GetExtension(buildPlayerOptions.locationPathName);
                buildDirectoryPath = Path.GetDirectoryName(buildPlayerOptions.locationPathName) + "\\";
                tempDirectoryPath = buildDirectoryPath + TempFolder;

                // Change Build Settings build directory to the temp directory
                // Generated location for the game is of the format "...BuildDirectory\temp\game\ProductName.extension"
                buildPlayerOptions.locationPathName =
                    tempDirectoryPath +
                    GameFolder +
                    fileName +
                    fileExtension;

                // Build the game
                BuildPipeline.BuildPlayer(buildPlayerOptions);
            }
            catch (BuildPlayerWindow.BuildMethodException)
            {
                // Exception called when the user manually closes the "File Chooser" window
                Debug.Log(logConjureArcade + "Build & Upload canceled.");
                return;
            }
            catch (Exception e)
            {
                ShowErrorDialog("An error occured when building the game.");
                Debug.LogError(e);
                return;
            }

            // "game" folder content is compressed
            CompressAndDelete(tempDirectoryPath + GameFolder, tempDirectoryPath + "game.zip");


            // Step 3: Copy images to the temp directory
            string mediasDirectoryPath = tempDirectoryPath + MediasFolder;
            string thumbnailPath = CopyAndRenameImage(metadata.Thumbnail, mediasDirectoryPath, "thumbnail");
            string gameplayImagePath = CopyAndRenameImage(metadata.GameplayImage, mediasDirectoryPath, "gameplayImage");


            // Step 4: Generate metadata inside the temp directory
            metadata.UpdateUneditableData();
            string metadataContent = GenerateMetadata(metadata, thumbnailPath, gameplayImagePath, fileName + fileExtension);
            if (!WriteMetadataFile(metadataContent, tempDirectoryPath))
            {
                ShowErrorDialog("An error occured when generating the metadata file.");
                return;
            }


            // Step 5: Convert all files int a ".conj"
            string conjFilePath = buildDirectoryPath + fileName + ".conj";
            CompressAndDelete(tempDirectoryPath, conjFilePath);


            // Step 6: Upload game and metadata to the webserver
            // TODO Add server connection / upload


            // Step 7: Show success feedback to the user
            Debug.Log(logConjureArcade + "Game was build and upload to the web server.");
            EditorUtility.DisplayDialog(
                "Success",
                "Game was build and upload to the web server.",
                "Ok");
        }

        private static void ShowErrorDialog(string description)
        {
            EditorUtility.DisplayDialog("Fail to Build and Upload Game", description, "Ok");
            Debug.LogError(logConjureArcade + description);
        }

        private static string CopyAndRenameImage(Texture2D image, string newDirectoryPath, string newFileName)
        {
            string relativePath = AssetDatabase.GetAssetPath(image);

            // We check and remove "Assets" at the start of the relative path because
            // Application.dataPath already gives us the path to the assets folder
            // Ex: Assets/Images/ --> Images/
            string oldAbsolutePath = Application.dataPath + relativePath.Substring(6);

            // We find the image, copy it to the new folder (newDirectoryPath), change its name and keep its extension
            FileInfo file = new FileInfo(oldAbsolutePath);
            string fullFileName = string.Format("{0}{1}", newFileName, file.Extension);
            if (file.Exists)
            {
                // Delete file in new directory if it already exists
                string newFilePath = string.Format("{0}{1}", newDirectoryPath, fullFileName);

                if (!Directory.Exists(newDirectoryPath))
                {
                    // Check if new directory exists, and create it
                    // If folder doesn't exist, the file cannot be copied
                    Directory.CreateDirectory(newDirectoryPath);
                }
                else if (File.Exists(newFilePath))
                {
                    // Check if file exists, and delete it
                    File.Delete(newFilePath);
                }

                file.CopyTo(newFilePath);
            }

            return fullFileName;
        }

        private string GenerateMetadata(
            ConjureArcadeMetadata metadata,
            string thumbnailFileName,
            string gameplayImageFileName,
            string fileName)
        {
            string newLine = Environment.NewLine;
            string content = "";
            content +=
                "id: " + metadata.Id + newLine +
                "game: " + metadata.GameTitle + newLine +
                "version: " + metadata.Version + newLine +
                "description: " + metadata.Description + newLine +
                "players: " + metadata.MinNumPlayer + "-" + metadata.MaxNumPlayer + newLine +
                "leaderboard: " + metadata.UseLeaderboard + newLine +
                "thumbnailPath: " + thumbnailFileName + newLine +
                "imagePath: " + gameplayImageFileName + newLine +
                "release: " + FormatDate(metadata.ReleaseDate) + newLine +
                "modification: " + FormatDate(metadata.LastGameUpdate) + newLine +
                "file: " + GameFolder + fileName + newLine;

            // Adding developers
            content += "developers: ";
            foreach (string developer in metadata.Developers)
            {
                content += developer + ", ";
            }
            content += newLine;

            // Adding genres
            content += "genres:" + newLine;
            foreach (GameGenre gameGenre in metadata.Genres)
            {
                string genre = ConjureArcadeMetadata.GenreOptions[gameGenre.selectedGenre];
                content += " " + genre + newLine;
            }

            return content;
        }

        private bool WriteMetadataFile(string content, string directoryPath)
        {
            string fullPath = directoryPath + MetadataFileName;

            try
            {
                if (File.Exists(fullPath))
                {
                    File.Delete(fullPath);
                }

                // Write content
                using (FileStream fs = File.Create(fullPath))
                {
                    byte[] encodedContent = new System.Text.UTF8Encoding(true).GetBytes(content);
                    fs.Write(encodedContent, 0, encodedContent.Length);
                }
            }
            catch (Exception e)
            {
                Debug.LogError(e.Message);
                return false;
            }

            return true;
        }

        private void CompressAndDelete(string sourceDirectoryPath, string destinationArchiveFileName)
        {
            ZipFile.CreateFromDirectory(sourceDirectoryPath, destinationArchiveFileName);
            Directory.Delete(sourceDirectoryPath, true);
        }

        private string FormatDate(DateTime date)
        {
            return
                date.Day.ToString() + "-" +
                date.Month.ToString() + "-" +
                date.Year.ToString();
        }
    }
}
#endif