using ERPCore.Domain.Entities;
using ERPCore.Domain.Enums;
using ERPCore.Repositories.Interfaces;
using ERPCore.Services.Interfaces;
using ERPCore.System.Errors;
using Microsoft.EntityFrameworkCore;

namespace ERPCore.Services;

public sealed class SalesDocumentWorkflowService : ISalesDocumentWorkflowService
{
    private readonly IRepository<SalesInvoice> _invoices;
    private readonly IRepository<SalesSlip> _slips;

    public SalesDocumentWorkflowService(IRepository<SalesInvoice> invoices, IRepository<SalesSlip> slips)
    {
        _invoices = invoices;
        _slips = slips;
    }

    public async Task<SalesInvoice> LoadEditableInvoiceAsync(int salesInvoiceId, uint expectedRowVersion, CancellationToken ct = default)
    {
        var invoice = await _invoices.Query().Include(x => x.Lines)
            .FirstOrDefaultAsync(x => x.SalesInvoiceId == salesInvoiceId, ct)
            ?? throw new NotFoundException($"Sales invoice {salesInvoiceId} was not found.");
        if (invoice.RowVersion != expectedRowVersion)
            throw new DomainException(ErrorCodes.ConcurrencyConflict, "The sales invoice was modified by another request.", 412);
        if (invoice.Status != SalesInvoiceStatus.Draft)
            throw new ConflictException($"Sales invoice {salesInvoiceId} is {invoice.Status} and cannot be edited.");
        return invoice;
    }

    public async Task<SalesSlip> LoadEditableSlipAsync(int salesSlipId, uint expectedRowVersion, CancellationToken ct = default)
    {
        var slip = await _slips.Query().Include(x => x.Lines)
            .FirstOrDefaultAsync(x => x.SalesSlipId == salesSlipId, ct)
            ?? throw new NotFoundException($"Sales slip {salesSlipId} was not found.");
        if (slip.RowVersion != expectedRowVersion)
            throw new DomainException(ErrorCodes.ConcurrencyConflict, "The sales slip was modified by another request.", 412);
        if (slip.Status != SalesSlipStatus.Draft)
            throw new ConflictException($"Sales slip {salesSlipId} is {slip.Status} and cannot be edited.");
        return slip;
    }
}
