using Microsoft.AspNetCore.Mvc; using TaskTracker.Core.DTOs; using TaskTracker.Core.Entities; using TaskTracker.Core.Interfaces; namespace TaskTracker.Api.Controllers; [ApiController] [Route("api/[controller]")] public class ContextController( IContextEventRepository contextRepo, IAppMappingRepository mappingRepo, ITaskRepository taskRepo, ILogger logger) : ControllerBase { [HttpPost] public async Task Ingest([FromBody] ContextEventRequest request) { // Try to auto-link to the active task var activeTask = await taskRepo.GetActiveTaskAsync(); var contextEvent = new ContextEvent { Source = request.Source, AppName = request.AppName, WindowTitle = request.WindowTitle, Url = request.Url, WorkTaskId = activeTask?.Id }; // Try to find a matching app mapping for category enrichment var mapping = await mappingRepo.FindMatchAsync(request.AppName, request.WindowTitle, request.Url); if (mapping is not null) { logger.LogDebug("Matched context event to category {Category} via {MatchType}", mapping.Category, mapping.MatchType); } var created = await contextRepo.CreateAsync(contextEvent); return Ok(ApiResponse.Ok(created)); } [HttpGet("recent")] public async Task GetRecent([FromQuery] int minutes = 30) { var events = await contextRepo.GetRecentAsync(minutes); return Ok(ApiResponse>.Ok(events)); } [HttpGet("summary")] public async Task GetSummary() { // Get today's events (last 8 hours) var events = await contextRepo.GetRecentAsync(480); var mappings = await mappingRepo.GetAllAsync(); var summary = events .GroupBy(e => e.AppName) .Select(g => { var match = mappings.FirstOrDefault(m => m.MatchType switch { "ProcessName" => g.Key.Contains(m.Pattern, StringComparison.OrdinalIgnoreCase), "TitleContains" => g.Any(e => e.WindowTitle.Contains(m.Pattern, StringComparison.OrdinalIgnoreCase)), "UrlContains" => g.Any(e => e.Url?.Contains(m.Pattern, StringComparison.OrdinalIgnoreCase) == true), _ => false }); return new ContextSummaryItem { AppName = match?.FriendlyName ?? g.Key, Category = match?.Category ?? "Unknown", EventCount = g.Count(), FirstSeen = g.Min(e => e.Timestamp), LastSeen = g.Max(e => e.Timestamp) }; }) .OrderByDescending(s => s.EventCount) .ToList(); return Ok(ApiResponse>.Ok(summary)); } }