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

namespace RothenburgAR.PointOfInterest
{
    public class PoiXmlPreloader : IPoiPreloader
    {
        public bool CanLoadPoiDirectory(string poiDirectory)
        {
            if (!Directory.Exists(poiDirectory))
                return false;

            string xmlFilePath = PathHelper.GetXmlPathFromDirectoryPath(poiDirectory);

            if (!File.Exists(xmlFilePath))
                return false;

            // Todo: More validations

            return true;
        }

        public List<PoiData> PreloadPoi(string poiDirectory)
        {
            string xmlFilePath = PathHelper.GetXmlPathFromDirectoryPath(poiDirectory);

            if (!File.Exists(xmlFilePath))
                throw new FileNotFoundException(xmlFilePath);

            XmlDocument doc = new XmlDocument();
            doc.Load(xmlFilePath);


            // Read the ID from the xml
            if (doc.DocumentElement == null || doc.DocumentElement.Attributes == null ||
                doc.DocumentElement.Attributes["id"] == null)
                throw new InvalidXMLException("Could not read doc.DocumentElement.Attributes['id] ");

            string poiId = doc.DocumentElement.Attributes["id"].Value;

            // Read the description from the xml
            XmlNodeList descNodes = doc.SelectNodes("//poi/description/text");
            TextElement descElement = TextElement.BuildFromXmlNode(poiDirectory, descNodes);

            // Read the title from the xml
            XmlNodeList titleNodes = doc.SelectNodes("//poi/title/text");
            TextElement titleElement = TextElement.BuildFromXmlNode(poiDirectory, titleNodes);


            PoiData poiData = new PoiData
            {
                ID = poiId,
                Description = descElement,
                Title = titleElement,
                SourcePath = poiDirectory
            };

            // Read the model value
            XmlNode modelNode = doc.SelectSingleNode("//poi/model");
            if (modelNode != null)
            {
                var pathNode = modelNode.SelectSingleNode("path");
                var scaleNode = modelNode.SelectSingleNode("scale");
                var rotationNode = modelNode.SelectSingleNode("rotation");
                var positionNode = modelNode.SelectSingleNode("position");

                var poiModelDescription = new PoiModelDescription
                {
                    ModelPath = PathHelper.CombinePaths(PathHelper.MediaPath, pathNode.Attributes["value"].Value, pathNode.Attributes["value"].Value + ".obj"),
                    ModelPrefabName = pathNode.Attributes["prefabName"].Value,
                    Scale = GetVector3FromXmlNode(scaleNode).GetValueOrDefault(Vector3.one),
                    Rotation = GetVector3FromXmlNode(rotationNode).GetValueOrDefault(Vector3.zero),
                    Position = GetVector3FromXmlNode(positionNode).GetValueOrDefault(Vector3.zero)
                };
                poiData.ModelDescription = poiModelDescription;
            }
            return new List<PoiData> { poiData };
        }

        private Vector3? GetVector3FromXmlNode(XmlNode node)
        {
            if (node == null)
                return null;
            if (node.Attributes == null)
                return null;
            if (node.Attributes["x"] == null)
                return null;
            if (node.Attributes["y"] == null)
                return null;
            if (node.Attributes["z"] == null)
                return null;

            try
            {
                float posX = float.Parse(node.Attributes["x"].Value,
                    CultureInfo.InvariantCulture.NumberFormat);
                float posY = float.Parse(node.Attributes["y"].Value,
                    CultureInfo.InvariantCulture.NumberFormat);
                float posZ = float.Parse(node.Attributes["z"].Value,
                    CultureInfo.InvariantCulture.NumberFormat);

                return new Vector3(posX, posY, posZ);
            }
            catch
            {
                // TODO: log error
                return null;
            }
        }
    }
}