using Kit.Helpers.Repository.Converter;
using System.Xml;

namespace Kit.Helpers.Repository.Xml
{
    public interface IXmlComplexFilter<TContentKey, TRootKey, TKey> : IXmlSimpleFilter<TContentKey, TKey>
    {
        TRootKey RootKeyId();
    }
    public abstract class XmlComplexClass<TKey, TRootKey, TContentKey> : XmlSimpleClass<TKey, TContentKey>, IRootXmlKey<TRootKey>
    {
        public TRootKey RootId { get; set; }
    }

    public abstract class EntityXmlSelectComplexRepository<TEntity, TFilter, TKey, TRootKey, TContextKey> :
       EntityXmlSelectSimpleRepository<TEntity, TFilter, TKey, TContextKey>
       where TFilter : IXmlComplexFilter<TContextKey, TRootKey, TKey>
       where TEntity : XmlComplexClass<TKey, TRootKey, TContextKey>
    {

        public EntityXmlSelectComplexRepository(string parentElementName, string path, string element, IConverter<XmlNode, TEntity> converter) : base(parentElementName, path, element)
        {
            _converter = converter;
        }

        public EntityXmlSelectComplexRepository(string path, string element, IConverter<XmlNode, TEntity> converter) : base(path, element)
        {
            _converter = converter;
        }


        public EntityXmlSelectComplexRepository(string element, IConverter<XmlNode, TEntity> converter) : base(element)
        {
            _converter = converter;
        }


        public EntityXmlSelectComplexRepository(string element) : base(element)
        {
        }

        public EntityXmlSelectComplexRepository(string path, string element) : base(path, element)
        {
        }

        public EntityXmlSelectComplexRepository(string rootElementName, string path, string element) : base(rootElementName, path, element)
        {
        }

        protected virtual XmlNodeList SelectNodesByKey(XmlDocument db, TKey key)
        {
            string xPath = $"{_elementName}";

            if (string.IsNullOrWhiteSpace(_path) == false)
            {
                xPath = $"{_path}/{xPath}";
            }

            if (xPath.StartsWith("/") == false)
            {
                xPath = "//" + xPath;
            }

            XmlNodeList list = db.SelectNodes($"{xPath}[@guid=\"{key}\"]");
            if (list.Count == 0)
            {
                list = db.SelectNodes($"{xPath}[@guid=\"{key.ToString().ToUpper()}\"]");
            }

            return list;
        }

        public virtual XmlNode GetRootNode(XmlDocument document, TRootKey key)
        {
            XmlNode result = document.SelectSingleNode("//*[@guid=\"{0}\"]".ApplyFormat(key.ToString()));
            if (result == null)
                result = document.SelectSingleNode("//*[@guid=\"{0}\"]".ApplyFormat(key.ToString().ToUpper()));
            if (!string.IsNullOrEmpty(_rootElementName))
            {
                var node = result.SelectSingleNode(_rootElementName);
                if (node == null)
                {
                    node = result.OwnerDocument.CreateElement(_rootElementName);
                    result.AppendChild(node);
                }
                result = node;
            }

            return result;
        }

        public override IQueryable<XmlNode> CreateQuery(XmlDocument db, TFilter filter)
        {
            XmlNode root = GetRootNode(db, filter.RootKeyId());
            if (root == null)
                root = db.CreateElement("Empty");
            XmlNode parent = GetParentNode(root);
            if (parent == null)
                parent = db.CreateElement("Empty");
            return parent.SelectNodes(this._elementName).Cast<XmlNode>().AsQueryable();
        }
    }
}
