using CashLineERP.Application.Identity;
using CashLineERP.Domain.Audit;
using Microsoft.EntityFrameworkCore;

namespace CashLineERP.Infrastructure.Persistence.Repositories;

public sealed class AccountingOfficeAuditRepository : IAccountingOfficeAuditRepository
{
    private const string ModuleCode = "ACCOUNTING_OFFICE";
    private const string EntityName = "ACCOUNTING_OFFICE_CLIENT";

    private readonly CashLineErpDbContext _dbContext;

    public AccountingOfficeAuditRepository(CashLineErpDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public void RecordAction(long accountingOfficeUserId, long targetPartyId, string actionCode, string? detailsText)
    {
        _dbContext.AuditEvents.Add(new AuditEvent(
            moduleCode: ModuleCode,
            entityName: EntityName,
            entityId: targetPartyId,
            actionCode: actionCode,
            actorUserId: accountingOfficeUserId,
            newValue: detailsText));
        _dbContext.SaveChanges();
    }

    public IReadOnlyCollection<AccountingOfficeDelegatedActivityView> GetActions(long accountingOfficeUserId, long? targetPartyId = null)
    {
        var usersById = _dbContext.Users.AsNoTracking().ToDictionary(entry => entry.Id);
        var partiesById = _dbContext.BusinessParties.AsNoTracking().ToDictionary(entry => entry.Id);

        return _dbContext.AuditEvents
            .AsNoTracking()
            .Where(entry => entry.ModuleCode == ModuleCode
                && entry.EntityName == EntityName
                && entry.ActorUserId == accountingOfficeUserId
                && (!targetPartyId.HasValue || entry.EntityId == targetPartyId.Value))
            .OrderByDescending(entry => entry.OccurredAtUtc)
            .ThenByDescending(entry => entry.Id)
            .ToArray()
            .Where(entry => usersById.ContainsKey(accountingOfficeUserId) && partiesById.ContainsKey(entry.EntityId))
            .Select(entry =>
            {
                var user = usersById[accountingOfficeUserId];
                var party = partiesById[entry.EntityId];
                return new AccountingOfficeDelegatedActivityView(
                    entry.Id,
                    entry.ActionCode,
                    accountingOfficeUserId,
                    user.LoginName,
                    user.DisplayName,
                    party.Id,
                    party.PartyCode,
                    party.PartyName,
                    entry.NewValue,
                    entry.OccurredAtUtc);
            })
            .ToArray();
    }
}
