// // Licensed to the .NET Foundation under one or more agreements.
// // The .NET Foundation licenses this file to you under the MIT license.
//
// using System;
// using System.Collections.Concurrent;
// using System.Collections.Generic;
// using System.Linq;
// using System.Threading;
// using System.Threading.Tasks;
// using FloraMultiPlatformFrontend.Application.Services.Interfaces;
// using FloraMultiPlatformFrontend.Data.Repositories.Interfaces;
// using Microsoft.EntityFrameworkCore;
// using Microsoft.Extensions.Logging;
//
// namespace FloraMultiPlatformFrontend.Data.Repositories;
//
// public class IoTagDataRepository : IIoTagDataRepository, IDisposable
// {
//     private readonly IDbContextFactory<FloraDbContext> _contextFactory;
//     private readonly ILogger<IoTagDataRepository> _logger;
//     private readonly IConfigurationService _configurationService;
//     private readonly IRefreshIntervalProvider _refreshIntervalProvider;
//     private readonly Timer _cacheRefreshTimer;
//     private readonly ConcurrentDictionary<int, Presentation.Models.IoTag.IoTagData> _ioTagCache = new();
//     private readonly SemaphoreSlim _cacheLock = new(1, 1);
//     private string? _currentMachineCode;
//
//     public IoTagDataRepository(
//         IDbContextFactory<FloraDbContext> contextFactory,
//         IConfigurationService configurationService,
//         IRefreshIntervalProvider refreshIntervalProvider,
//         ILogger<IoTagDataRepository> logger
//     )
//     {
//         _contextFactory = contextFactory ?? throw new ArgumentNullException(nameof(contextFactory));
//         _configurationService = configurationService ?? throw new ArgumentNullException(nameof(configurationService));
//         _refreshIntervalProvider = refreshIntervalProvider ?? throw new ArgumentNullException(nameof(refreshIntervalProvider));
//         _logger = logger ?? throw new ArgumentNullException(nameof(logger));
//
//         _cacheRefreshTimer = new Timer(RefreshCache, null, TimeSpan.Zero, _refreshIntervalProvider.DiagnosisInterval);
//         _configurationService.SelectedMachineChanged += OnSelectedMachineChanged;
//         _ = InitializeCacheAsync();
//     }
//
//     private async void OnSelectedMachineChanged(object? sender, EventArgs e)
//     {
//         await InitializeCacheAsync();
//     }
//
//     private async Task InitializeCacheAsync()
//     {
//         var machine = await _configurationService.GetSelectedMachineAsync();
//         var newMachineCode = machine?.Code;
//
//         if (_currentMachineCode != newMachineCode)
//         {
//             _logger.LogInformation("Machine code changed from {OldMachineCode} to {NewMachineCode}. Resetting IO tag data cache.", _currentMachineCode, newMachineCode);
//             _currentMachineCode = newMachineCode;
//             _ioTagCache.Clear();
//             _cacheRefreshTimer.Change(TimeSpan.Zero, _refreshIntervalProvider.DiagnosisInterval);
//         }
//     }
//
//     private async void RefreshCache(object? state)
//     {
//         if (string.IsNullOrEmpty(_currentMachineCode))
//         {
//             _logger.LogWarning("Skipping IO tag data cache refresh because machine code is not set.");
//             return;
//         }
//
//         if (!await _cacheLock.WaitAsync(TimeSpan.FromSeconds(1)))
//         {
//             _logger.LogWarning("Could not acquire cache lock to refresh IO tag data. Skipping this cycle.");
//             return;
//         }
//
//         try
//         {
//             _logger.LogDebug("Starting IO tag data cache refresh for machine {MachineCode}", _currentMachineCode);
//             var serverName = await _configurationService.GetMachineServerNameAsync();
//             var tagConfig = await _configurationService.GetTagConfigurationAsync();
//             var ioTablePrefix = tagConfig?.IOTablePrefix ?? "IO";
//             var tableName = $"{serverName}_{_currentMachineCode}_{ioTablePrefix}";
//             var query = $@"
//                 SELECT ID, tagValue, tagTime
//                 FROM [{tableName}]";
//
//             using var context = await _contextFactory.CreateDbContextAsync();
//             var rawData = await context.Database.SqlQueryRaw<RawIoTagData>(query).ToListAsync();
//
//             foreach (var d in rawData)
//             {
//                 _ioTagCache[d.ID] = MapToIoTagData(d);
//             }
//             _logger.LogInformation("IO tag data cache refreshed with {Count} items for machine {MachineCode}", _ioTagCache.Count, _currentMachineCode);
//         }
//         catch (Exception ex)
//         {
//             _logger.LogError(ex, "Error refreshing IO tag data cache for machine {MachineCode}", _currentMachineCode);
//         }
//         finally
//         {
//             _cacheLock.Release();
//         }
//     }
//
//     public Task<IEnumerable<Presentation.Models.IoTag.IoTagData>> GetIoTagDataAsync(
//         IEnumerable<int> tagIds,
//         string machineCode,
//         CancellationToken cancellationToken = default
//     )
//     {
//         // if (_currentMachineCode != machineCode)
//         // {
//         //     _logger.LogWarning("Requested machine code {RequestedMachineCode} does not match current machine code {CurrentMachineCode}. Returning empty list.", machineCode, _currentMachineCode);
//         //     return Task.FromResult(Enumerable.Empty<Presentation.Models.IoTag.IoTagData>());
//         // }
//
//         var idList = tagIds.ToList();
//         var results = new List<Presentation.Models.IoTag.IoTagData>(idList.Count);
//         foreach (var id in idList)
//         {
//             if (_ioTagCache.TryGetValue(id, out var ioTagData))
//             {
//                 results.Add(ioTagData);
//             }
//         }
//         return Task.FromResult<IEnumerable<Presentation.Models.IoTag.IoTagData>>(results);
//     }
//
//     public Task<Presentation.Models.IoTag.IoTagData?> GetIoTagDataByIdAsync(
//         int tagId,
//         string machineCode,
//         CancellationToken cancellationToken = default
//     )
//     {
//         if (_currentMachineCode != machineCode)
//         {
//             _logger.LogWarning("Requested machine code {RequestedMachineCode} does not match current machine code {CurrentMachineCode}. Returning null.", machineCode, _currentMachineCode);
//             return Task.FromResult<Presentation.Models.IoTag.IoTagData?>(null);
//         }
//
//         _ioTagCache.TryGetValue(tagId, out var ioTagData);
//         return Task.FromResult(ioTagData);
//     }
//
//     public Task<IEnumerable<Presentation.Models.IoTag.IoTagData>> GetAllIoTagDataAsync(
//         string machineCode,
//         CancellationToken cancellationToken = default
//     )
//     {
//         // if (_currentMachineCode != machineCode)
//         // {
//         //     _logger.LogWarning("Requested machine code {RequestedMachineCode} does not match current machine code {CurrentMachineCode}. Returning empty list.", machineCode, _currentMachineCode);
//         //     return Task.FromResult(Enumerable.Empty<Presentation.Models.IoTag.IoTagData>());
//         // }
//
//         return Task.FromResult<IEnumerable<Presentation.Models.IoTag.IoTagData>>(_ioTagCache.Values);
//     }
//
//     private static Presentation.Models.IoTag.IoTagData MapToIoTagData(RawIoTagData rawData)
//     {
//         return new Presentation.Models.IoTag.IoTagData
//         {
//             Id = rawData.ID,
//             TagValue = rawData.tagValue ?? false,
//             TagTime = rawData.tagTime
//         };
//     }
//
//     /// <summary>
//     /// Raw data class for mapping SQL query results.
//     /// </summary>
//     private class RawIoTagData
//     {
//         public int ID { get; set; }
//         public bool? tagValue { get; set; }
//         public DateTime? tagTime { get; set; }
//     }
//     public void Dispose()
//     {
//         _cacheRefreshTimer?.Dispose();
//         _configurationService.SelectedMachineChanged -= OnSelectedMachineChanged;
//         _cacheLock?.Dispose();
//     }
// }
