using ERPCore.Domain.Entities;
using ERPCore.Domain.Enums;
using ERPCore.Dtos.Common;
using ERPCore.Dtos.Reference;
using ERPCore.Infra.UoW;
using ERPCore.Repositories.Interfaces;
using ERPCore.Services.Interfaces;
using ERPCore.System.Errors;
using Microsoft.EntityFrameworkCore;

namespace ERPCore.Services;

public sealed class ReasonCodeService : IReasonCodeService
{
    private readonly IRepository<ReasonCode> _codes;
    private readonly IUnitOfWork _uow;

    public ReasonCodeService(IRepository<ReasonCode> codes, IUnitOfWork uow)
    {
        _codes = codes;
        _uow = uow;
    }

    public async Task<PagedResponse<ReasonCodeDto>> ListAsync(ReasonContext? context, PageQuery query, CancellationToken ct = default)
    {
        var q = _codes.Query().AsNoTracking();
        if (context is not null) q = q.Where(r => r.Context == context);

        var total = await q.CountAsync(ct);
        var rows = await q.OrderBy(r => r.Context).ThenBy(r => r.Code)
            .Skip(query.Skip).Take(query.PageSize)
            .Select(r => new ReasonCodeDto(r.ReasonCodeId, r.Code, r.Description, r.Context))
            .ToListAsync(ct);

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

    public async Task<ReasonCodeDto> CreateAsync(CreateReasonCodeRequest request, CancellationToken ct = default)
    {
        var code = request.Code.Trim().ToUpperInvariant();
        if (await _codes.Query().AnyAsync(r => r.Context == request.Context && r.Code == code, ct))
            throw new ConflictException($"Reason code '{code}' already exists in context {request.Context}.");

        var entity = new ReasonCode { Code = code, Description = request.Description.Trim(), Context = request.Context };
        await _codes.AddAsync(entity, ct);
        await _uow.SaveChangesAsync(ct);

        return new ReasonCodeDto(entity.ReasonCodeId, entity.Code, entity.Description, entity.Context);
    }
}
