using System;
using System.Collections;
using System.Collections.Generic;
using HeurekaGames.AssetHunterPRO.BaseTreeviewImpl.AssetTreeView;
using UnityEngine;
using UnityEditor;
using System.Linq;
using HeurekaGames.AssetHunterPRO.BaseTreeviewImpl;
using System.IO;

namespace HeurekaGames.AssetHunterPRO
{
    [System.Serializable]
    public class AH_TreeViewSelectionInfo
    {
        public delegate void AssetDeletedHandler();
        public static event AssetDeletedHandler OnAssetDeleted;

        private bool hasSelection;
        public bool HasSelection
        {
            get
            {
                return hasSelection;
            }
        }

        public const float Height = 64;

        private AH_MultiColumnHeader multiColumnHeader;
        private List<AH_TreeviewElement> selection;

        internal void Reset()
        {
            selection = null;
            hasSelection = false;
        }

        internal void SetSelection(AH_TreeViewWithTreeModel treeview, IList<int> selectedIds)
        {
            multiColumnHeader = (AH_MultiColumnHeader)(treeview.multiColumnHeader);
            selection = new List<AH_TreeviewElement>();

            foreach (var itemID in selectedIds)
            {
                selection.Add(treeview.treeModel.Find(itemID));
            }

            hasSelection = (selection.Count > 0);

            //If we have more, select the assets in project view
            if (hasSelection)
            {
                if (selection.Count > 1)
                {
                    UnityEngine.Object[] selectedObjects = new UnityEngine.Object[selection.Count];
                    for (int i = 0; i < selection.Count; i++)
                    {
                        selectedObjects[i] = AssetDatabase.LoadMainAssetAtPath(selection[i].RelativePath);
                    }
                    Selection.objects = selectedObjects;
                }
                else
                    Selection.activeObject = AssetDatabase.LoadMainAssetAtPath(selection[0].RelativePath);

                AH_Utils.PingObjectAtPath(selection[selection.Count - 1].RelativePath, false);
            }
        }

        internal void OnGUISelectionInfo(Rect selectionRect)
        {
            GUILayout.BeginArea(selectionRect);
            //TODO MAKE SURE WE DONT DO ALL OF THIS EACH FRAME, BUT CACHE THE SELECTION DATA

            using (new EditorGUILayout.HorizontalScope())
            {
                if (selection.Count == 1)
                {
                    drawSingle();
                }
                else
                {
                    drawMulti();
                }
            }
            GUILayout.EndArea();
        }

        private void drawSingle()
        {

            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.BeginVertical();
            drawAssetPreview(true);
            EditorGUILayout.EndVertical();

            //Draw info from single asset
            EditorGUILayout.BeginVertical();

            GUILayout.Label(selection[0].RelativePath);
            if (!selection[0].IsFolder)
            {
                GUILayout.Label("(" + selection[0].AssetType + ")");
            }

            EditorGUILayout.EndVertical();
            GUILayout.FlexibleSpace();
            if (selection[0].IsFolder)
                DrawDeleteFolderButton(selection[0]);
            else
                drawDeleteAssetsButton();


            EditorGUILayout.EndHorizontal();
        }

        private void drawMulti()
        {
            //Make sure we have not selected folders
            bool allFolders = selection.All(val => val.IsFolder);
            bool allFiles = !selection.Any(val => val.IsFolder);
            var allSameType = selection.All(var => var.AssetType == selection[0].AssetType);

            //Find if we have selected nested assets or folders
            var containsNested = selection.Any(file => selection.Any(y => file != y && (y.RelativePath.StartsWith(file.RelativePath) && y.RelativePath.Split(Path.DirectorySeparatorChar).Length != file.RelativePath.Split(Path.DirectorySeparatorChar).Length)));

            drawAssetPreview(allSameType);

            EditorGUILayout.BeginHorizontal();
            //Draw info from multiple
            EditorGUILayout.BeginVertical();

            //Identical files
            if (allSameType && allFiles)
            {
                GUILayout.Label(selection[0].AssetType.ToString() + " (" + selection.Count() + ")");
            }
            //all folders
            else if (allSameType)
            {
                GUILayout.Label("Folders (" + selection.Count() + ")");
            }
            //Non identical selection
            else
            {
                GUILayout.Label("Items (" + selection.Count() + ")");
            }

            EditorGUILayout.EndVertical();

            if (!containsNested)
                drawDeleteAssetsButton();

            EditorGUILayout.EndHorizontal();
        }

        private void drawDeleteAssetsButton()
        {
            if (multiColumnHeader.ShowMode != AH_MultiColumnHeader.AssetShowMode.Unused)
                return;

            long combinedSize = 0;
            foreach (var item in selection)
            {
                if (item.IsFolder)
                    combinedSize += item.GetFileSizeRecursively(AH_MultiColumnHeader.AssetShowMode.Unused);
                else
                    combinedSize += item.FileSize;
            }
            if (GUILayout.Button("Delete " + (AH_Utils.GetSizeAsString(combinedSize)), GUILayout.Width(160), GUILayout.Height(32)))
                deleteUnusedAssets();
        }

        private void DrawDeleteFolderButton(AH_TreeviewElement folder)
        {
            if (multiColumnHeader.ShowMode != AH_MultiColumnHeader.AssetShowMode.Unused)
                return;

            string description = "Delete unused assets from folder";
            GUIContent content = new GUIContent("Delete " + (AH_Utils.GetSizeAsString(folder.GetFileSizeRecursively(AH_MultiColumnHeader.AssetShowMode.Unused))), description);
            GUIStyle style = new GUIStyle(GUI.skin.button);
            DrawDeleteFolderButton(content, folder, style, description, "Do you want to delete all unused assets from:" + Environment.NewLine + folder.RelativePath, GUILayout.Width(160), GUILayout.Height(32));
        }

        public void DrawDeleteFolderButton(GUIContent content, AH_TreeviewElement folder, GUIStyle style, string dialogHeader, string dialogDescription, params GUILayoutOption[] layout)
        {
            if (GUILayout.Button(content, style, layout))
                deleteUnusedFromFolder(dialogHeader, dialogDescription, folder);
        }

        private void drawAssetPreview(bool bDraw)
        {
            GUIContent content = new GUIContent();

            //Draw asset preview
            if (bDraw && !selection[0].IsFolder)
            {
                var preview = AssetPreview.GetAssetPreview(AssetDatabase.LoadMainAssetAtPath(selection[0].RelativePath));
                content = new GUIContent(preview);
            }
            //Draw Folder icon
            else if (bDraw)
                content = EditorGUIUtility.IconContent("Folder Icon");

            GUILayout.Label(content,GUILayout.Width(Height), GUILayout.Height(Height));
        }

        private void deleteUnusedAssets()
        {
            int choice = EditorUtility.DisplayDialogComplex("Delete unused assets", "Do you want to delete the selected assets", "Yes", "Cancel", "Backup");
            List<string> affectedAssets = new List<string>();

            if (choice == 0)//Delete
            {
                foreach (var item in selection)
                {
                    affectedAssets.Add(item.RelativePath);
                }
                deleteMultipleAssets(affectedAssets);
            }
            else if (choice == 2)//Backup
            {
                foreach (var item in selection)
                {
                    affectedAssets.Add(item.RelativePath);
                    exportAssetsToPackage("Backup as unitypackage", affectedAssets);
                }
            }
        }

        private void deleteUnusedFromFolder(AH_TreeviewElement folder)
        {
            deleteUnusedFromFolder("Delete unused assets from folder", "Do you want to delete all unused assets from:" + Environment.NewLine + folder.RelativePath, folder);
        }

        private void deleteUnusedFromFolder(string header, string description, AH_TreeviewElement folder)
        {
            int choice = EditorUtility.DisplayDialogComplex(header, description, "Yes", "Cancel", "Backup (Slow)");

            List<string> affectedAssets = new List<string>();
            if (choice != 1)//Not Cancel
            {
                //Collect affected assets
                affectedAssets = folder.GetUnusedPathsRecursively();
            }
            if (choice == 0)//Delete
            {
                deleteMultipleAssets(affectedAssets);
            }
            else if (choice == 2)//Backup
            {
                exportAssetsToPackage("Backup as unitypackage", affectedAssets);
            }
        }

        private void exportAssetsToPackage(string header, List<string> affectedAssets)
        {
            string filename = Environment.UserName + "_Backup_" + "_" + AH_SerializationHelper.GetDateString();
            string savePath = EditorUtility.SaveFilePanel(
            header,
            AH_SerializationHelper.GetBackupFolder(),
            filename,
            "unitypackage");

            if (!string.IsNullOrEmpty(savePath))
            {
                EditorUtility.DisplayProgressBar("Backup", "Creating backup of " + affectedAssets.Count() + " assets", 0f);
                AssetDatabase.ExportPackage(affectedAssets.ToArray<string>(), savePath, ExportPackageOptions.Default);
                EditorUtility.ClearProgressBar();
                EditorUtility.RevealInFinder(savePath);

                deleteMultipleAssets(affectedAssets);
            }
        }

        private void deleteMultipleAssets(List<string> affectedAssets)
        {
            double startTime = EditorApplication.timeSinceStartup;

            for (int i = 0; i < affectedAssets.Count(); i++)
            {
                EditorUtility.DisplayProgressBar("Deleting unused assets", "Deleting " + i + "/" + affectedAssets.Count() + Environment.NewLine + affectedAssets[i], ((float)i) / ((float)affectedAssets.Count()));
            }
#if UNITY_2020_1_OR_NEWER
            List<string> failedPaths = new List<string>();
            AssetDatabase.DeleteAssets(affectedAssets.ToArray(), failedPaths);
#else
            foreach (var asset in affectedAssets)
            {
                AssetDatabase.DeleteAsset(asset);
            }
#endif

            EditorUtility.ClearProgressBar();

            AssetDatabase.Refresh();

            if (OnAssetDeleted != null)
                OnAssetDeleted();
        }
    }
}