using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using RothenburgAR.Common;
using UnityEngine;

namespace RothenburgAR.Exhibition
{
    public class ExhibitionManager : Singleton<ExhibitionManager>
    {
        private List<string> ExhibitionSourcePathList { get; set; }
        private List<IExhibitionPreloader> ExhibitionPreloaderList { get; set; }
        private Dictionary<string, ExhibitionBehaviour> ExhibitionList { get; set; }

        public ExhibitionManager()
        {
            ExhibitionSourcePathList = new List<string>();
            ExhibitionPreloaderList = new List<IExhibitionPreloader>();
            ExhibitionList = new Dictionary<string, ExhibitionBehaviour>();
        }


        public void AddExhibitionSourcePath(string path)
        {
            // Todo: Throw Exception
            if (Directory.Exists(path))
            {
                ExhibitionSourcePathList.Add(path);
                Debug.Log("AddExhibitionSourcePath: Added source path '" + path + "'");
            }
            else
            {
                Debug.Log("AddExhibitionSourcePath: Path '" + path + "'; does not exist - ignoring");
            }
        }

        public void LoadEverySourcePath(Action<int, int, int, int> progressCallback)
        {
            StartCoroutine(LoadEverySourcePathCoroutine(progressCallback));
        }

        private IEnumerator LoadEverySourcePathCoroutine(Action<int, int, int, int> progressCallback)
        {
            int listLength = ExhibitionSourcePathList.Count;
            int currentIndex = 0;

            foreach (var s in ExhibitionSourcePathList)
            {
                currentIndex++;
                var index = currentIndex;
                LoadSourcePath(s,
                               (int subMax, int subCurrent) =>
                               {
                                   progressCallback(listLength, index, subMax, subCurrent);
                               });
                yield return null;
            }
        }


        public void LoadEverySourcePath()
        {
            Debug.Log("Loading every path");
            ExhibitionSourcePathList.ForEach(LoadSourcePath);
        }

        public void LoadSourcePath(string path, Action<int, int> progressCallback)
        {
            StartCoroutine(LoadSourcePathCoroutine(path, progressCallback));
        }

        private IEnumerator LoadSourcePathCoroutine(string path, Action<int, int> progressCallback)
        {
            if (!Directory.Exists(path))
            {
                Debug.Log("LoadSourcePath: Path '" + path + "'; does not exist - aborting");
            }
            else
            {
                var dirs = Directory.GetDirectories(path);
                int max = dirs.Length;
                int current = 0;

                progressCallback(max, 0);
                foreach (var directory in dirs)
                {
                    yield return null;
                    LoadExhibitionFromDirectPath(directory);
                    progressCallback(max, ++current);
                }
            }
        }

        public void LoadSourcePath(string path)
        {
            if (!Directory.Exists(path))
            {
                Debug.Log("LoadSourcePath: Path '" + path + "'; does not exist - aborting");
                return;
            }

            foreach (var directory in Directory.GetDirectories(path))
            {
                LoadExhibitionFromDirectPath(directory);
            }
        }

        private void LoadExhibitionFromDirectPath(string path)
        {
            if (!Directory.Exists(path))
            {
                Debug.Log("LoadExhibitionFromDirectPath: Path '" + path + "'; does not exist - aborting");
                return;
            }
            IExhibitionPreloader preloader = SelectExhibitionPreloader(path);
            if (preloader == null)
            {
                Debug.LogWarning("Could not find a valid preloader for path '" + path + "'; Ignoring");
                return;
            }
            try
            {
                PreloadedExhibition preloadedExhibition = preloader.PreloadExhibition(path);
                if (ExhibitionList.ContainsKey(preloadedExhibition.ID))
                {
                    Debug.LogWarning("Exhibition with ID '" + preloadedExhibition.ID + "' already exists! Ignoring '" +
                                     path + "'");
                    return;
                }

                Debug.Log("BUILD; " + preloadedExhibition.ID);
                var exhibitionBehaviour = ExhibitionFactory.BuildExhibition(preloadedExhibition);

                ExhibitionList.Add(exhibitionBehaviour.ID, exhibitionBehaviour);
                Debug.Log("Added new exhibition with ID '" + exhibitionBehaviour.ID + "' from '" + path + "'");
            }
            catch (Exception e)
            {
                Debug.LogError("Could not load path '" + path + "'; Ignoring; Error: " + e.Message);
            }
        }

        private IExhibitionPreloader SelectExhibitionPreloader(string path)
        {
            IExhibitionPreloader selectedPreloader = null;
            // Find a valid preloader
            foreach (var preloader in ExhibitionPreloaderList)
            {
                if (preloader.CanLoadExhibitionDirectory(path))
                {
                    selectedPreloader = preloader;
                    break;
                }
            }
            return selectedPreloader;
        }


        public void AddExhibitionPreloader(IExhibitionPreloader preloader)
        {
            ExhibitionPreloaderList.Add(preloader);
        }

        public void ClearExhibitionList()
        {
            ExhibitionList.Clear();
        }

        public void ClearSourcePathList()
        {
            ExhibitionSourcePathList.Clear();
        }

        public void ClearExhibitionPreloaderList()
        {
            ExhibitionPreloaderList.Clear();
        }

        public void ClearAll()
        {
            ClearExhibitionList();
            ClearExhibitionPreloaderList();
            ClearSourcePathList();
        }
    }
}