using Disco.Plugins.ServiceTracker.Models; using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; using System.Linq; namespace Disco.Plugins.ServiceTracker.Services { public class ServiceTrackerDataStore { private readonly string _dataDirectory; private readonly string _ticketsPath; private readonly string _configPath; private readonly string _externalPath; private static readonly object _lock = new object(); public ServiceTrackerDataStore(string pluginDataDirectory) { _dataDirectory = pluginDataDirectory; _ticketsPath = Path.Combine(_dataDirectory, "tickets.json"); _configPath = Path.Combine(_dataDirectory, "config.json"); _externalPath = Path.Combine(_dataDirectory, "external_tickets.json"); if (!Directory.Exists(_dataDirectory)) Directory.CreateDirectory(_dataDirectory); } public string DataDirectory { get { return _dataDirectory; } } // --- Configuration --- public ServiceTrackerConfig LoadConfig() { lock (_lock) { if (!File.Exists(_configPath)) { var def = ServiceTrackerConfig.CreateDefault(); SaveConfig(def); return def; } var json = File.ReadAllText(_configPath); var config = JsonConvert.DeserializeObject(json); if (config == null) return ServiceTrackerConfig.CreateDefault(); // Ensure new fields have defaults if (config.Technicians == null) config.Technicians = new List(); if (config.GoogleSheet == null) config.GoogleSheet = new GoogleSheetConfig(); if (string.IsNullOrEmpty(config.DiscoBaseUrl)) config.DiscoBaseUrl = "http://disco:9292"; if (config.DetailInactivitySeconds <= 0) config.DetailInactivitySeconds = 300; return config; } } public void SaveConfig(ServiceTrackerConfig config) { lock (_lock) { var json = JsonConvert.SerializeObject(config, Formatting.Indented); File.WriteAllText(_configPath, json); } } // --- Disco Tickets --- public List LoadAllTickets() { lock (_lock) { if (!File.Exists(_ticketsPath)) return new List(); var json = File.ReadAllText(_ticketsPath); return JsonConvert.DeserializeObject>(json) ?? new List(); } } public ServiceTicket GetTicket(int jobId) { return LoadAllTickets().FirstOrDefault(t => t.JobId == jobId); } public void SaveTicket(ServiceTicket ticket) { lock (_lock) { var tickets = LoadAllTicketsUnsafe(); var idx = tickets.FindIndex(t => t.JobId == ticket.JobId); ticket.LastModifiedDate = DateTime.Now; if (idx >= 0) tickets[idx] = ticket; else tickets.Add(ticket); SaveAllTicketsUnsafe(tickets); } } public void DeleteTicket(int jobId) { lock (_lock) { var tickets = LoadAllTicketsUnsafe(); tickets.RemoveAll(t => t.JobId == jobId); SaveAllTicketsUnsafe(tickets); } } public void AddNote(int jobId, TicketNote note) { lock (_lock) { var tickets = LoadAllTicketsUnsafe(); var ticket = tickets.FirstOrDefault(t => t.JobId == jobId); if (ticket != null) { if (ticket.Notes == null) ticket.Notes = new List(); ticket.Notes.Add(note); ticket.LastModifiedDate = DateTime.Now; SaveAllTicketsUnsafe(tickets); } } } // --- External Tickets (Google Sheet) --- public List LoadExternalTickets() { lock (_lock) { if (!File.Exists(_externalPath)) return new List(); var json = File.ReadAllText(_externalPath); return JsonConvert.DeserializeObject>(json) ?? new List(); } } public void SaveExternalTickets(List tickets) { lock (_lock) { var json = JsonConvert.SerializeObject(tickets, Formatting.Indented); File.WriteAllText(_externalPath, json); } } public ServiceTicket GetExternalTicket(int internalId) { return LoadExternalTickets().FirstOrDefault(t => t.JobId == internalId); } public void SaveExternalTicket(ServiceTicket ticket) { lock (_lock) { var tickets = LoadExternalTicketsUnsafe(); var idx = tickets.FindIndex(t => t.JobId == ticket.JobId); ticket.LastModifiedDate = DateTime.Now; if (idx >= 0) tickets[idx] = ticket; else tickets.Add(ticket); var json = JsonConvert.SerializeObject(tickets, Formatting.Indented); File.WriteAllText(_externalPath, json); } } public void AddExternalNote(int internalId, TicketNote note) { lock (_lock) { var tickets = LoadExternalTicketsUnsafe(); var ticket = tickets.FirstOrDefault(t => t.JobId == internalId); if (ticket != null) { if (ticket.Notes == null) ticket.Notes = new List(); ticket.Notes.Add(note); ticket.LastModifiedDate = DateTime.Now; var json = JsonConvert.SerializeObject(tickets, Formatting.Indented); File.WriteAllText(_externalPath, json); } } } // Internal (caller must hold lock) private List LoadAllTicketsUnsafe() { if (!File.Exists(_ticketsPath)) return new List(); var json = File.ReadAllText(_ticketsPath); return JsonConvert.DeserializeObject>(json) ?? new List(); } private void SaveAllTicketsUnsafe(List tickets) { var json = JsonConvert.SerializeObject(tickets, Formatting.Indented); File.WriteAllText(_ticketsPath, json); } private List LoadExternalTicketsUnsafe() { if (!File.Exists(_externalPath)) return new List(); var json = File.ReadAllText(_externalPath); return JsonConvert.DeserializeObject>(json) ?? new List(); } } }