using Microsoft.Extensions.Logging;
using Kit.Helpers.Repository;

namespace Kit.Helpers.Service
{
    public interface ISQLiteVersionService
    {
        void AppendType(FileContentSqlite fileContentSqlite, string fileTypeKey);
        bool UpdateByTypes(FileContentSqlite fileContentSqlite);

        int GetRowVersion(FileContentSqlite fileContentSqlite);
        void SetRowVersion(FileContentSqlite fileContentSqlite, int rowVersion);
    }

    public class SQLiteVersionService : ISQLiteVersionService
    {
        private ISQLiteVersionRepository _fileVersionRepository;
        private ISQLiteGlobalVarRepository _sqLiteGlobalVarRepository;
        private IDictionary<string, List<ISQLiteVersionUpdateItem>> _updateItems;
        private IDictionary<string, int> _latestVersions;
        public SQLiteVersionService(
            ISQLiteVersionRepository fileVersionRepository,
            ISQLiteGlobalVarRepository sqLiteGlobalVarRepository,
            IEnumerable<ISQLiteVersionUpdateItem> updateItems
        )
        {
            _fileVersionRepository = fileVersionRepository;
            _sqLiteGlobalVarRepository = sqLiteGlobalVarRepository;
            _updateItems = updateItems?.GroupBy(x => x.FileTypeKey ?? string.Empty).ToDictionary(x => x.Key, x => x.ToList()) ?? new Dictionary<string, List<ISQLiteVersionUpdateItem>>();
            _latestVersions = _updateItems.ToDictionary(x => x.Key, x => x.Value.Max(y => y.NewVersion));
        }

        public void AppendType(FileContentSqlite fileContentSqlite, string fileTypeKey)
        {
            SQLiteFileVersionInfo? sqlFileVersionInfo = _fileVersionRepository.Select(fileContentSqlite).SingleOrDefault(x => x.Type == fileTypeKey);
            if (sqlFileVersionInfo == null)
            {
                _fileVersionRepository.Set(fileContentSqlite, new SQLiteFileVersionInfo { Type = fileTypeKey, Version = 0 });
            }
        }

        public bool UpdateByTypes(FileContentSqlite fileContentSqlite)
        {
            IEnumerable<SQLiteFileVersionInfo> fileVersionInfos = _fileVersionRepository.Select(fileContentSqlite);
            Check.IsNotNullOrEmpty(fileVersionInfos, "В файле не указана информация о версиях компонентов");

            bool isUpdated = false;

            fileVersionInfos.ForEach(fileVersionInfo =>
            {
                /// Если информации по типу нет - выходим
                if (_latestVersions.ContainsKey(fileVersionInfo.Type) == false)
                {
                    return;
                }
                /// Если файл по этому типу уже актуальный - выходим
                if (_latestVersions[fileVersionInfo.Type] == fileVersionInfo.Version)
                {
                    return;
                }

                /// Элементы для обновления по типу
                IEnumerable<ISQLiteVersionUpdateItem>? updateItems = _updateItems[fileVersionInfo.Type];

                SQLiteFileVersionInfo fileVersionInfoIter = fileVersionInfo;
                ISQLiteVersionUpdateItem? updateItem = null;

                /// Обновляемся до актуальной версии по типу
                do
                {
                    updateItem = updateItems.FirstOrDefault(x => x.OldVersion == fileVersionInfoIter.Version);
                    if (updateItem != null)
                    {
                        updateItem.Execute(fileContentSqlite);
                        fileVersionInfoIter = new SQLiteFileVersionInfo { Type = fileVersionInfo.Type, Version = updateItem.NewVersion };
                        _fileVersionRepository.Set(fileContentSqlite, fileVersionInfoIter);
                        isUpdated = true;
                    }
                }
                while (updateItem != null);
            });

#if DEBUG
            fileVersionInfos = _fileVersionRepository.Select(fileContentSqlite);
#endif

            return isUpdated;
        }

        public int GetRowVersion(FileContentSqlite fileContentSqlite)
        {
            return _sqLiteGlobalVarRepository.Get(fileContentSqlite, "row_version").TryParseToInt32(0);
        }

        public void SetRowVersion(FileContentSqlite fileContentSqlite, int rowVersion)
        {
            _sqLiteGlobalVarRepository.Set(fileContentSqlite, "row_version", rowVersion.ToString());
        }
    }
}