using Books.Api.Domain.Products.Events;
using EventFlow.Aggregates;

namespace Books.Api.Domain.Products;

public class ProductAggregate(ProductId id) : AggregateRoot<ProductAggregate, ProductId>(id),
    IEmit<ProductCreatedEvent>,
    IEmit<ProductUpdatedEvent>,
    IEmit<ProductDeactivatedEvent>,
    IEmit<ProductReactivatedEvent>
{
    private bool _isCreated;
    private bool _isActive = true;

    public void Apply(ProductCreatedEvent e)
    {
        _isCreated = true;
    }

    public void Apply(ProductUpdatedEvent e) { }

    public void Apply(ProductDeactivatedEvent e) => _isActive = false;

    public void Apply(ProductReactivatedEvent e) => _isActive = true;

    public void Create(
        string companyId,
        string? productNumber,
        string name,
        string? description,
        decimal unitPrice,
        string vatCode,
        string? unit,
        string? defaultAccountId,
        string? ean,
        string? manufacturer)
    {
        if (_isCreated)
            throw new DomainException("PRODUCT_EXISTS", "Product already exists", "Produktet eksisterer allerede");

        if (string.IsNullOrWhiteSpace(companyId))
            throw new DomainException("COMPANY_REQUIRED", "Company ID is required", "Virksomheds-ID er paakraevet");

        if (string.IsNullOrWhiteSpace(name))
            throw new DomainException("PRODUCT_NAME_REQUIRED", "Product name is required", "Produktnavn er paakraevet");

        if (unitPrice < 0)
            throw new DomainException("INVALID_UNIT_PRICE", "Unit price cannot be negative", "Enhedspris kan ikke vaere negativ");

        if (string.IsNullOrWhiteSpace(vatCode))
            throw new DomainException("VAT_CODE_REQUIRED", "VAT code is required", "Momskode er paakraevet");

        Emit(new ProductCreatedEvent(
            companyId,
            productNumber?.Trim(),
            name.Trim(),
            description?.Trim(),
            unitPrice,
            vatCode,
            unit?.Trim(),
            defaultAccountId,
            ean?.Trim(),
            manufacturer?.Trim()));
    }

    public void Update(
        string? productNumber,
        string name,
        string? description,
        decimal unitPrice,
        string vatCode,
        string? unit,
        string? defaultAccountId,
        string? ean,
        string? manufacturer)
    {
        EnsureCanModify();

        if (string.IsNullOrWhiteSpace(name))
            throw new DomainException("PRODUCT_NAME_REQUIRED", "Product name is required", "Produktnavn er paakraevet");

        if (unitPrice < 0)
            throw new DomainException("INVALID_UNIT_PRICE", "Unit price cannot be negative", "Enhedspris kan ikke vaere negativ");

        if (string.IsNullOrWhiteSpace(vatCode))
            throw new DomainException("VAT_CODE_REQUIRED", "VAT code is required", "Momskode er paakraevet");

        Emit(new ProductUpdatedEvent(
            productNumber?.Trim(),
            name.Trim(),
            description?.Trim(),
            unitPrice,
            vatCode,
            unit?.Trim(),
            defaultAccountId,
            ean?.Trim(),
            manufacturer?.Trim()));
    }

    public void Deactivate()
    {
        EnsureCanModify();

        if (!_isActive)
            throw new DomainException("PRODUCT_ALREADY_INACTIVE",
                "Product is already inactive",
                "Produktet er allerede inaktivt");

        Emit(new ProductDeactivatedEvent());
    }

    public void Reactivate()
    {
        if (!_isCreated)
            throw new DomainException("PRODUCT_NOT_FOUND",
                "Product does not exist",
                "Produktet findes ikke");

        if (_isActive)
            throw new DomainException("PRODUCT_ALREADY_ACTIVE",
                "Product is already active",
                "Produktet er allerede aktivt");

        Emit(new ProductReactivatedEvent());
    }

    private void EnsureCanModify()
    {
        if (!_isCreated)
            throw new DomainException("PRODUCT_NOT_FOUND",
                "Product does not exist",
                "Produktet findes ikke");
    }
}
