using Microsoft.EntityFrameworkCore;
using ROLAC.API.Data.Logging;
using ROLAC.API.DTOs.Logging;
using ROLAC.API.DTOs.Shared;
using ROLAC.API.Entities.Logging;

namespace ROLAC.API.Services.Logging;

public interface ISystemLogQueryService
{
    Task<PagedResult<SystemLogListItemDto>> GetPagedAsync(SystemLogQuery query);
    Task<SystemLogDetailDto?> GetByIdAsync(long id);
}

/// <summary>Read-only, paged access to the SystemLogs table via the dedicated LogDbContext.</summary>
public sealed class SystemLogQueryService : ISystemLogQueryService
{
    private readonly LogDbContext _db;

    public SystemLogQueryService(LogDbContext db) => _db = db;

    public async Task<PagedResult<SystemLogListItemDto>> GetPagedAsync(SystemLogQuery query)
    {
        var page     = Math.Max(1, query.Page);
        var pageSize = Math.Clamp(query.PageSize, 1, 200);

        var rows = _db.SystemLogs.AsNoTracking().AsQueryable();

        if (query.From is not null)  rows = rows.Where(l => l.Timestamp >= query.From);
        if (query.To   is not null)  rows = rows.Where(l => l.Timestamp <= query.To);
        if (query.Level is not null) rows = rows.Where(l => l.Level == query.Level);
        else if (query.MinLevel is not null) rows = rows.Where(l => l.Level >= query.MinLevel);
        if (!string.IsNullOrWhiteSpace(query.UserId))
            rows = rows.Where(l => l.UserId == query.UserId);
        if (!string.IsNullOrWhiteSpace(query.CorrelationId))
            rows = rows.Where(l => l.CorrelationId == query.CorrelationId);
        if (!string.IsNullOrWhiteSpace(query.Search))
        {
            var term = query.Search.Trim().ToLower();
            rows = rows.Where(l =>
                l.Message.ToLower().Contains(term) || l.Category.ToLower().Contains(term));
        }

        var total = await rows.CountAsync();
        var items = await rows
            .OrderByDescending(l => l.Timestamp)
            .Skip((page - 1) * pageSize).Take(pageSize)
            .Select(l => new SystemLogListItemDto
            {
                Id            = l.Id,
                Timestamp     = l.Timestamp,
                Level         = l.Level.ToString(),
                Category      = l.Category,
                Message       = l.Message,
                HasException  = l.Exception != null,
                StatusCode    = l.StatusCode,
                RequestPath   = l.RequestPath,
                HttpMethod    = l.HttpMethod,
                UserId        = l.UserId,
                CorrelationId = l.CorrelationId,
            })
            .ToListAsync();

        return new PagedResult<SystemLogListItemDto>
        {
            Items = items, TotalCount = total, Page = page, PageSize = pageSize,
        };
    }

    public async Task<SystemLogDetailDto?> GetByIdAsync(long id)
    {
        return await _db.SystemLogs.AsNoTracking()
            .Where(l => l.Id == id)
            .Select(l => new SystemLogDetailDto
            {
                Id            = l.Id,
                Timestamp     = l.Timestamp,
                Level         = l.Level.ToString(),
                Category      = l.Category,
                Message       = l.Message,
                HasException  = l.Exception != null,
                StatusCode    = l.StatusCode,
                RequestPath   = l.RequestPath,
                HttpMethod    = l.HttpMethod,
                UserId        = l.UserId,
                CorrelationId = l.CorrelationId,
                EventId       = l.EventId,
                Exception     = l.Exception,
                IpAddress     = l.IpAddress,
            })
            .FirstOrDefaultAsync();
    }
}
