using MySqlConnector;
using UtopiaCanteenSystem.Models;
namespace UtopiaCanteenSystem.Services;
///
/// Meal schedule CRUD against production HRMS MySQL table hrms.meal_schedule.
/// Uses IConfigService.GetHrmsLookupConnectionString() (same DB as employee lookup).
/// Schema: id (bigint), meal_name (varchar), start_time (time), end_time (time), created_at, updated_at, location_site_id (int).
/// No is_active column; all rows are treated as active.
///
public class ProductionMealScheduleService : IMealScheduleService
{
private readonly IConfigService _configService;
private const string TableRef = "`hrms`.`meal_schedule`";
public ProductionMealScheduleService(IConfigService configService)
{
_configService = configService;
}
///
public IReadOnlyList GetActiveSchedulesForSite(string siteId)
{
var connStr = _configService.GetHrmsLookupConnectionString();
if (string.IsNullOrWhiteSpace(connStr))
return Array.Empty();
var siteIdInt = SiteIdStringToInt(siteId);
var list = new List();
try
{
using var conn = new MySqlConnection(connStr);
conn.Open();
var sql = $"SELECT id, meal_name, start_time, end_time, created_at, updated_at, location_site_id FROM {TableRef} WHERE location_site_id = @siteId ORDER BY start_time";
using var cmd = new MySqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@siteId", siteIdInt);
using var r = cmd.ExecuteReader();
while (r.Read())
list.Add(ReadRow(r));
}
catch
{
return Array.Empty();
}
return list;
}
///
public async Task> GetAllSchedulesAsync(CancellationToken cancellationToken = default)
{
var connStr = _configService.GetHrmsLookupConnectionString();
if (string.IsNullOrWhiteSpace(connStr))
return Array.Empty();
var list = new List();
await using var conn = new MySqlConnection(connStr);
await conn.OpenAsync(cancellationToken).ConfigureAwait(false);
var sql = $"SELECT id, meal_name, start_time, end_time, created_at, updated_at, location_site_id FROM {TableRef} ORDER BY location_site_id, start_time";
await using var cmd = new MySqlCommand(sql, conn);
await using var r = await cmd.ExecuteReaderAsync(cancellationToken).ConfigureAwait(false);
while (await r.ReadAsync(cancellationToken).ConfigureAwait(false))
list.Add(ReadRow(r));
return list;
}
///
public async Task CreateAsync(MealSchedule schedule, CancellationToken cancellationToken = default)
{
var connStr = _configService.GetHrmsLookupConnectionString();
if (string.IsNullOrWhiteSpace(connStr))
throw new InvalidOperationException("HRMS MySQL connection string not configured.");
var utc = DateTime.UtcNow;
var mealName = MealSessionToName(schedule.MealSession);
var siteIdInt = SiteIdStringToInt(schedule.LocationSiteId);
await using var conn = new MySqlConnection(connStr);
await conn.OpenAsync(cancellationToken).ConfigureAwait(false);
var sql = $@"INSERT INTO {TableRef} (meal_name, start_time, end_time, created_at, updated_at, location_site_id)
VALUES (@mealName, @startTime, @endTime, @createdAt, @updatedAt, @siteId)";
await using var cmd = new MySqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@mealName", mealName);
cmd.Parameters.AddWithValue("@startTime", schedule.StartTime?.Trim() ?? "00:00:00");
cmd.Parameters.AddWithValue("@endTime", schedule.EndTime?.Trim() ?? "23:59:59");
cmd.Parameters.AddWithValue("@createdAt", utc);
cmd.Parameters.AddWithValue("@updatedAt", utc);
cmd.Parameters.AddWithValue("@siteId", siteIdInt);
await cmd.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false);
return cmd.LastInsertedId;
}
///
public async Task UpdateAsync(MealSchedule schedule, CancellationToken cancellationToken = default)
{
var connStr = _configService.GetHrmsLookupConnectionString();
if (string.IsNullOrWhiteSpace(connStr))
throw new InvalidOperationException("HRMS MySQL connection string not configured.");
var utc = DateTime.UtcNow;
var mealName = MealSessionToName(schedule.MealSession);
var siteIdInt = SiteIdStringToInt(schedule.LocationSiteId);
await using var conn = new MySqlConnection(connStr);
await conn.OpenAsync(cancellationToken).ConfigureAwait(false);
var sql = $@"UPDATE {TableRef} SET meal_name = @mealName, start_time = @startTime, end_time = @endTime, location_site_id = @siteId, updated_at = @updatedAt WHERE id = @id";
await using var cmd = new MySqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@id", schedule.Id);
cmd.Parameters.AddWithValue("@mealName", mealName);
cmd.Parameters.AddWithValue("@startTime", schedule.StartTime?.Trim() ?? "00:00:00");
cmd.Parameters.AddWithValue("@endTime", schedule.EndTime?.Trim() ?? "23:59:59");
cmd.Parameters.AddWithValue("@siteId", siteIdInt);
cmd.Parameters.AddWithValue("@updatedAt", utc);
await cmd.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false);
}
///
public async Task DeleteAsync(long id, CancellationToken cancellationToken = default)
{
var connStr = _configService.GetHrmsLookupConnectionString();
if (string.IsNullOrWhiteSpace(connStr))
throw new InvalidOperationException("HRMS MySQL connection string not configured.");
await using var conn = new MySqlConnection(connStr);
await conn.OpenAsync(cancellationToken).ConfigureAwait(false);
var sql = $"DELETE FROM {TableRef} WHERE id = @id";
await using var cmd = new MySqlCommand(sql, conn);
cmd.Parameters.AddWithValue("@id", id);
await cmd.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(false);
}
/// Read row: id (bigint), meal_name, start_time (time), end_time (time), created_at, updated_at, location_site_id (int).
private static MealSchedule ReadRow(MySqlDataReader r)
{
return new MealSchedule
{
Id = r.GetInt64(0),
MealSession = MealNameToSession(GetString(r, 1)),
StartTime = GetTimeString(r, 2),
EndTime = GetTimeString(r, 3),
CreatedAt = GetDateTime(r, 4),
UpdatedAt = GetDateTime(r, 5),
LocationSiteId = IntToSiteIdString(r.IsDBNull(6) ? 0 : r.GetInt32(6)),
IsActive = true
};
}
private static string GetString(MySqlDataReader r, int i)
{
if (r.IsDBNull(i)) return "";
return r.GetString(i) ?? "";
}
private static string GetTimeString(MySqlDataReader r, int i)
{
if (r.IsDBNull(i)) return "00:00:00";
var v = r.GetValue(i);
if (v is TimeSpan ts)
return ts.ToString(@"hh\:mm\:ss");
return v?.ToString()?.Trim() ?? "00:00:00";
}
private static DateTime GetDateTime(MySqlDataReader r, int i)
{
if (r.IsDBNull(i)) return DateTime.UtcNow;
var dt = r.GetDateTime(i);
return dt.Kind == DateTimeKind.Utc ? dt : DateTime.SpecifyKind(dt, DateTimeKind.Utc);
}
private static int MealNameToSession(string mealName)
{
if (string.IsNullOrWhiteSpace(mealName)) return 0;
var n = mealName.Trim();
if (n.Equals("Breakfast", StringComparison.OrdinalIgnoreCase) || n.Equals("BreakFast", StringComparison.OrdinalIgnoreCase)) return (int)MealSession.Breakfast;
if (n.Equals("Lunch", StringComparison.OrdinalIgnoreCase)) return (int)MealSession.Lunch;
if (n.Equals("Tea", StringComparison.OrdinalIgnoreCase)) return (int)MealSession.Tea;
if (n.Equals("Dinner", StringComparison.OrdinalIgnoreCase)) return (int)MealSession.Dinner;
return 0;
}
private static string MealSessionToName(int mealSession)
{
return mealSession switch
{
(int)MealSession.Breakfast => "Breakfast",
(int)MealSession.Lunch => "Lunch",
(int)MealSession.Tea => "Tea",
(int)MealSession.Dinner => "Dinner",
_ => "Breakfast"
};
}
private static int SiteIdStringToInt(string siteId)
{
var s = (siteId ?? "").Trim();
if (string.IsNullOrEmpty(s)) return 0;
var digits = new string(s.Where(char.IsDigit).ToArray());
return int.TryParse(digits, out var n) ? n : 0;
}
/// Normalize production location_site_id int to display string (e.g. 2 -> "02").
private static string IntToSiteIdString(int siteIdInt)
{
if (siteIdInt <= 0) return "01";
return siteIdInt <= 99 ? siteIdInt.ToString("D2") : siteIdInt.ToString();
}
}