using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Xml;
using Newtonsoft.Json;
using RothenburgAR.Common;
using RothenburgAR.Updater;
using UnityEngine;

namespace RothenburgAR.Exhibition
{
    public class ExhibitionApiDataPreloader : IExhibitionPreloader
    {
        public bool CanLoadExhibitionDirectory(string exhibitionDirectory)
        {
            if (!Directory.Exists(exhibitionDirectory))
                return false;
            if (!File.Exists(Path.Combine(exhibitionDirectory, "version.txt")))
                return false;
            if (!File.Exists(Path.Combine(exhibitionDirectory, "tracker.xml")))
                return false;
            if (!File.Exists(Path.Combine(exhibitionDirectory, "tracker.dat")))
                return false;

            var languageDirs = new DirectoryInfo(exhibitionDirectory).GetDirectories().Select(d => d.Name).ToList();
            foreach (var dir in languageDirs)
            {
                var metaFilePath = PathHelper.CombinePaths(exhibitionDirectory, dir, "meta.json");
                if (!File.Exists(metaFilePath)) return false;
            }

            // Todo: More validations
            return true;
        }

        public PreloadedExhibition PreloadExhibition(string exhibitionDirectory)
        {
            //throw new System.NotImplementedException();

            Dictionary<string, List<ApiExhibit>> exhibits = new Dictionary<string, List<ApiExhibit>>();

            var languageDirs = new DirectoryInfo(exhibitionDirectory).GetDirectories().Select(d => d.Name).ToList();
            foreach (var lang in languageDirs)
            {
                var metaFilePath = PathHelper.CombinePaths(exhibitionDirectory, lang, "meta.json");
                if (!File.Exists(metaFilePath)) continue;
                var exhibitList = JsonConvert.DeserializeObject<List<ApiExhibit>>(File.ReadAllText(metaFilePath, System.Text.Encoding.UTF8));
                exhibits.Add(lang, exhibitList);
            }

            var exhibitIds = exhibits.Values.SelectMany(l => l.Select(e => e.Id)).Distinct().ToList();

            string exhibitionId = new DirectoryInfo(exhibitionDirectory).Name;
            PreloadedExhibition resultExhibition = new PreloadedExhibition
            {
                ContainedExhibits = new List<PreloadedExhibit>(),
                ID = exhibitionId,
                DatasetPath = exhibitionDirectory
            };

            foreach (var exhibitId in exhibitIds)
            {
                var newExhibit = PreloadExhibit(exhibits, exhibitId);
                resultExhibition.ContainedExhibits.Add(newExhibit);
            }
            return resultExhibition;
        }

        private PreloadedExhibit PreloadExhibit(Dictionary<string, List<ApiExhibit>> exhibits, string exhibitId)
        {
            PreloadedExhibit newExhibit = new PreloadedExhibit();

            newExhibit.ID = exhibitId;
            newExhibit.ReferencedPoiEntries = new List<PreloadedPoiReference>();

            // Load Description Text

            TextElement exhibitDescr = new TextElement();
            TextElement exhibitTitle = new TextElement();
            foreach (var exhibitPerLang in exhibits)
            {
                var exhibit = exhibitPerLang.Value.FirstOrDefault(e => e.Id == exhibitId);
                if (exhibit == null) continue;

                exhibitDescr.AddTextElement(exhibitPerLang.Key, TextEntryType.Inline, exhibit.Description);
                exhibitTitle.AddTextElement(exhibitPerLang.Key, TextEntryType.Inline, exhibit.Title);
            }
            newExhibit.Description = exhibitDescr;

            //TODO calculate sizes dynamically and remove these default values
            var position = new Vector3(0, .1f, -.52f);
            var rotation = Vector3.zero;
            var fontSize = .7f;
            var boxHeight = .25f;
            var boxWidth = .75f;

            PreloadedExhibitTitle preTitle = new PreloadedExhibitTitle
            {
                Text = exhibitTitle,
                Position = position,
                Rotation = rotation,
                FontSize = fontSize,
                BoxWidth = boxWidth,
                BoxHeight = boxHeight
            };
            newExhibit.Title = preTitle;

            var pois = exhibits
                .SelectMany(e => e.Value)
                .Where(e => e.Id == exhibitId)
                .SelectMany(e => e.Pois)
                .Distinct()
                .ToList();

            foreach (var poi in pois)
            {
                var poiReference = new PreloadedPoiReference
                {
                    ReferencedId = poi.Id,
                    Position = new Vector3(poi.X, 0, poi.Y),
                    Rotation = Vector3.zero,
                    Scale = Vector3.one
                };
                newExhibit.ReferencedPoiEntries.Add(poiReference);
            }

            return newExhibit;
        }
    }
}