using System.Text.Json;
using ERPCore.Domain.Entities;
using ERPCore.Dtos.Audit;
using ERPCore.Dtos.Common;
using ERPCore.Repositories.Interfaces;
using ERPCore.Services.Interfaces;
using Microsoft.EntityFrameworkCore;

namespace ERPCore.Services;

public sealed class AuditService : IAuditService
{
    private readonly IRepository<AuditLog> _logs;
    private readonly IRepository<JournalEntryStub> _journal;

    public AuditService(IRepository<AuditLog> logs, IRepository<JournalEntryStub> journal)
    {
        _logs = logs;
        _journal = journal;
    }

    public async Task<PagedResponse<AuditLogDto>> ListLogsAsync(
        string? entityType, int? entityId, int? userId, DateOnly? from, DateOnly? to, PageQuery query, CancellationToken ct = default)
    {
        var q = _logs.Query().AsNoTracking();
        if (!string.IsNullOrWhiteSpace(entityType)) q = q.Where(l => l.EntityType == entityType);
        if (entityId is not null) q = q.Where(l => l.EntityId == entityId);
        if (userId is not null) q = q.Where(l => l.UserId == userId);
        if (from is not null) q = q.Where(l => l.CreatedAt >= from.Value.ToDateTime(TimeOnly.MinValue));
        if (to is not null) q = q.Where(l => l.CreatedAt < to.Value.AddDays(1).ToDateTime(TimeOnly.MinValue));

        var total = await q.CountAsync(ct);
        var rows = await q.OrderByDescending(l => l.AuditId)
            .Skip(query.Skip).Take(query.PageSize).ToListAsync(ct);

        var dtos = rows.Select(l => new AuditLogDto(
            l.AuditId, l.UserId, l.EntityType, l.EntityId, l.Action,
            JsonSerializer.Deserialize<JsonElement>(l.ChangeSet), l.CreatedAt)).ToList();

        return PagedResponse<AuditLogDto>.Create(dtos, query.Page, query.PageSize, total);
    }

    public async Task<PagedResponse<JournalEntryStubDto>> ListJournalAsync(
        string? sourceDocType, int? sourceDocId, PageQuery query, CancellationToken ct = default)
    {
        var q = _journal.Query().AsNoTracking();
        if (!string.IsNullOrWhiteSpace(sourceDocType)) q = q.Where(j => j.SourceDocType == sourceDocType);
        if (sourceDocId is not null) q = q.Where(j => j.SourceDocId == sourceDocId);

        var total = await q.CountAsync(ct);
        var rows = await q.OrderByDescending(j => j.JournalId)
            .Skip(query.Skip).Take(query.PageSize)
            .Select(j => new JournalEntryStubDto(j.JournalId, j.SourceDocType, j.SourceDocId, j.DebitAccount, j.CreditAccount, j.Amount))
            .ToListAsync(ct);

        return PagedResponse<JournalEntryStubDto>.Create(rows, query.Page, query.PageSize, total);
    }
}
