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

namespace Kit.Helpers.Service
{
    public interface IXmlVersionService
    {
        string? GetFileType(XmlDocument document);
        void SetFileType(XmlDocument document, string fileTypeKey, int version = 0, bool rewriteIfExist = false);
        void Init(XmlDocument document, string fileTypeKey);
        bool Update(XmlDocument document);
    }

    public class XmlVersionService : IXmlVersionService
    {
        private IXmlFileVersionRepository _fileVersionRepository;
        private IDictionary<string, List<IXmlVersionUpdateItem>> _updateItems;
        public XmlVersionService(IXmlFileVersionRepository fileVersionRepository, IEnumerable<IXmlVersionUpdateItem> updateItems)
        {
            _fileVersionRepository = fileVersionRepository;
            _updateItems = updateItems?.GroupBy(x => x.FileTypeKey ?? string.Empty).ToDictionary(x => x.Key, x => x.ToList()) ?? new Dictionary<string, List<IXmlVersionUpdateItem>>();
        }

        public string? GetFileType(XmlDocument document)
        {
            return _fileVersionRepository.Get(document)?.Type;
        }

        public void SetFileType(XmlDocument document, string fileTypeKey, int version = 0, bool rewriteIfExist = true)
        {
            var fileVersion = _fileVersionRepository.Get(document);

            if (rewriteIfExist || fileVersion == null)
            {
                _fileVersionRepository.Set(document, new XmlFileVersionInfo { Type = fileTypeKey, Version = version });
            }
        }

        private bool ModifyFile(XmlDocument document, XmlFileVersionInfo fileVersionInfo)
        {
            IEnumerable<IXmlVersionUpdateItem>? updateItems = _updateItems[fileVersionInfo.Type];
            if (updateItems.IsNullOrEmpty()) return false;

            XmlFileVersionInfo fileVersionInfoIter = fileVersionInfo;
            IXmlVersionUpdateItem? updateItem = null;

            bool isUpdated = false;

            do
            {
                updateItem = updateItems.FirstOrDefault(x => x.OldVersion == fileVersionInfoIter.Version);
                if (updateItem != null)
                {
                    updateItem.Execute(document);
                    fileVersionInfoIter = new XmlFileVersionInfo { Type = fileVersionInfo.Type, Version = updateItem.NewVersion };
                    _fileVersionRepository.Set(document, fileVersionInfoIter);
                    isUpdated = true;
                }
            }
            while (updateItem != null);

            return isUpdated;
        }

        public void Init(XmlDocument document, string fileTypeKey)
        {
            ModifyFile(document, new XmlFileVersionInfo { Type = fileTypeKey, Version = 0 });
        }

        public bool Update(XmlDocument document)
        {
            XmlFileVersionInfo? fileVersionInfo = _fileVersionRepository.Get(document);
            if (fileVersionInfo == null) throw new Exception("В файле не указана информация о версии");
            if (string.IsNullOrWhiteSpace(fileVersionInfo.Type)) throw new Exception("В версии файла не указана информация о типе файла");

            if (_updateItems.ContainsKey(fileVersionInfo.Type) == false) throw new Exception($"В системе отсутствует информация о методах обновления версии файла указанного типа");

            return ModifyFile(document, fileVersionInfo);
        }
    }
}