using MySqlConnector;
using System.Collections.Concurrent;
using System.Net.Http;
using System.Text;
namespace UtopiaCanteenSystem.Services;
///
/// Fetches employee photo from hrms.employee_photo by parent_document_id (employee document id from lookup).
/// Handles data URI (data:image/...;base64,...) or raw image bytes. Caches by key to avoid repeated DB calls.
///
public class EmployeePhotoService : IEmployeePhotoService
{
private readonly IConfigService _configService;
private readonly ConcurrentDictionary _cache = new(StringComparer.OrdinalIgnoreCase);
private const int MaxCacheEntries = 50;
private readonly HttpClient _httpClient;
public EmployeePhotoService(IConfigService configService, HttpClient httpClient)
{
_configService = configService;
_httpClient = httpClient;
_httpClient = httpClient;
}
///
//public async Task GetPhotoBytesAsync(string parentDocumentId, CancellationToken cancellationToken = default)
//{
// if (string.IsNullOrWhiteSpace(parentDocumentId))
// return null;
// var key = parentDocumentId.Trim();
// if (_cache.TryGetValue(key, out var cached))
// return cached;
// var connectionString = _configService.GetHrmsLookupConnectionString();
// if (string.IsNullOrWhiteSpace(connectionString))
// return null;
// try
// {
// await using var conn = new MySqlConnection(connectionString);
// await conn.OpenAsync(cancellationToken).ConfigureAwait(false);
// // employee_photo.employee_id stores the employee document id (parent_document_id from employee lookup)
// const string sql = "SELECT photo_blob FROM hrms.employee_photo WHERE employee_id = @parentDocumentId LIMIT 1";
// await using var cmd = new MySqlCommand(sql, conn);
// cmd.Parameters.AddWithValue("@parentDocumentId", key);
// await using var reader = await cmd.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false);
// if (!await reader.ReadAsync(cancellationToken).ConfigureAwait(false))
// return null;
// if (reader.IsDBNull(0))
// return null;
// byte[] blob;
// try
// {
// var len = reader.GetBytes(0, 0, null, 0, 0);
// blob = new byte[len];
// reader.GetBytes(0, 0, blob, 0, (int)len);
// }
// catch
// {
// return null;
// }
// var imageBytes = DecodeBlobToImageBytes(blob);
// if (imageBytes == null || imageBytes.Length == 0)
// return null;
// // Cache (evict old if needed)
// while (_cache.Count >= MaxCacheEntries && _cache.Count > 0)
// {
// var first = _cache.Keys.FirstOrDefault();
// if (first != null)
// _cache.TryRemove(first, out _);
// else
// break;
// }
// _cache[key] = imageBytes;
// return imageBytes;
// }
// catch
// {
// return null;
// }
//}
public async Task GetPhotoBytesAsync(string parentDocumentId, CancellationToken cancellationToken = default)
{
if (string.IsNullOrWhiteSpace(parentDocumentId))
return null;
var key = parentDocumentId.Trim();
if (_cache.TryGetValue(key, out var cached))
return cached;
try
{
var url = $"https://portal.utopiaindustries.pk/uind/employee-photo/{Uri.EscapeDataString(key)}.jpeg";
using var response = await _httpClient.GetAsync(url, cancellationToken).ConfigureAwait(false);
if (!response.IsSuccessStatusCode)
return null;
var contentType = response.Content.Headers.ContentType?.MediaType;
if (!string.IsNullOrWhiteSpace(contentType) &&
!contentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase))
{
return null;
}
var imageBytes = await response.Content.ReadAsByteArrayAsync(cancellationToken).ConfigureAwait(false);
if (imageBytes == null || imageBytes.Length == 0)
return null;
while (_cache.Count >= MaxCacheEntries && _cache.Count > 0)
{
var first = _cache.Keys.FirstOrDefault();
if (first != null)
_cache.TryRemove(first, out _);
else
break;
}
_cache[key] = imageBytes;
return imageBytes;
}
catch
{
return null;
}
}
///
/// Converts blob to image bytes: if blob is UTF-8 "data:image...;base64,<payload>", decodes base64; else treats as raw image.
///
internal static byte[]? DecodeBlobToImageBytes(byte[] blob)
{
if (blob == null || blob.Length == 0)
return null;
try
{
var str = Encoding.UTF8.GetString(blob);
if (str.StartsWith("data:image", StringComparison.OrdinalIgnoreCase))
{
var commaIndex = str.IndexOf(',');
if (commaIndex < 0)
return null;
var base64 = str.Substring(commaIndex + 1).Trim();
return Convert.FromBase64String(base64);
}
return blob;
}
catch
{
return null;
}
}
}