using Books.Api.Domain.Companies;
using Books.Api.Domain.Customers.Events;
using EventFlow.Aggregates;

namespace Books.Api.Domain.Customers;

public class CustomerAggregate(CustomerId id) : AggregateRoot<CustomerAggregate, CustomerId>(id),
    IEmit<CustomerCreatedEvent>,
    IEmit<CustomerUpdatedEvent>,
    IEmit<CustomerDeactivatedEvent>,
    IEmit<CustomerReactivatedEvent>
{
    private bool _isCreated;
    private bool _isActive = true;
    private CustomerType _customerType;

    public void Apply(CustomerCreatedEvent e)
    {
        _isCreated = true;
        _customerType = e.CustomerType;
    }

    public void Apply(CustomerUpdatedEvent e) { }

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

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

    public void Create(
        string companyId,
        string customerNumber,
        CustomerType customerType,
        string name,
        string? cvr,
        string? address,
        string? postalCode,
        string? city,
        string country,
        string? email,
        string? phone,
        int paymentTermsDays,
        string? defaultRevenueAccountId,
        string subLedgerAccountId)
    {
        if (_isCreated)
            throw new DomainException("CUSTOMER_EXISTS", "Customer already exists", "Kunden eksisterer allerede");

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

        if (string.IsNullOrWhiteSpace(customerNumber))
            throw new DomainException("CUSTOMER_NUMBER_REQUIRED", "Customer number is required", "Kundenummer er paakraevet");

        if (string.IsNullOrWhiteSpace(name))
            throw new DomainException("CUSTOMER_NAME_REQUIRED", "Customer name is required", "Kundenavn er paakraevet");

        if (string.IsNullOrWhiteSpace(subLedgerAccountId))
            throw new DomainException("SUB_LEDGER_ACCOUNT_REQUIRED", "Sub-ledger account ID is required", "Debitor-underkonto er paakraevet");

        // B2B customers require CVR
        if (customerType == CustomerType.Business && string.IsNullOrWhiteSpace(cvr))
            throw new DomainException("CVR_REQUIRED_FOR_BUSINESS",
                "CVR is required for business customers",
                "CVR-nummer er paakraevet for erhvervskunder");

        // Validate CVR format if provided
        if (!string.IsNullOrWhiteSpace(cvr))
        {
            if (!CvrValidator.HasValidFormat(cvr))
                throw new DomainException("INVALID_CVR_FORMAT",
                    "CVR number must be exactly 8 digits",
                    "CVR-nummer skal vaere praecis 8 cifre");

            if (!CvrValidator.IsValid(cvr))
                throw new DomainException("INVALID_CVR_CHECKSUM",
                    "CVR number has invalid checksum",
                    "CVR-nummer har ugyldig kontrolsum");
        }

        if (paymentTermsDays < 0 || paymentTermsDays > 365)
            throw new DomainException("INVALID_PAYMENT_TERMS",
                "Payment terms must be between 0 and 365 days",
                "Betalingsbetingelser skal vaere mellem 0 og 365 dage");

        Emit(new CustomerCreatedEvent(
            companyId,
            customerNumber.Trim(),
            customerType,
            name.Trim(),
            cvr?.Trim(),
            address?.Trim(),
            postalCode?.Trim(),
            city?.Trim(),
            country,
            email?.Trim(),
            phone?.Trim(),
            paymentTermsDays,
            defaultRevenueAccountId,
            subLedgerAccountId));
    }

    public void Update(
        string name,
        string? cvr,
        string? address,
        string? postalCode,
        string? city,
        string country,
        string? email,
        string? phone,
        int paymentTermsDays,
        string? defaultRevenueAccountId)
    {
        EnsureCanModify();

        if (string.IsNullOrWhiteSpace(name))
            throw new DomainException("CUSTOMER_NAME_REQUIRED", "Customer name is required", "Kundenavn er paakraevet");

        // B2B customers still require CVR
        if (_customerType == CustomerType.Business && string.IsNullOrWhiteSpace(cvr))
            throw new DomainException("CVR_REQUIRED_FOR_BUSINESS",
                "CVR is required for business customers",
                "CVR-nummer er paakraevet for erhvervskunder");

        // Validate CVR if provided
        if (!string.IsNullOrWhiteSpace(cvr))
        {
            if (!CvrValidator.HasValidFormat(cvr))
                throw new DomainException("INVALID_CVR_FORMAT",
                    "CVR number must be exactly 8 digits",
                    "CVR-nummer skal vaere praecis 8 cifre");

            if (!CvrValidator.IsValid(cvr))
                throw new DomainException("INVALID_CVR_CHECKSUM",
                    "CVR number has invalid checksum",
                    "CVR-nummer har ugyldig kontrolsum");
        }

        if (paymentTermsDays < 0 || paymentTermsDays > 365)
            throw new DomainException("INVALID_PAYMENT_TERMS",
                "Payment terms must be between 0 and 365 days",
                "Betalingsbetingelser skal vaere mellem 0 og 365 dage");

        Emit(new CustomerUpdatedEvent(
            name.Trim(),
            cvr?.Trim(),
            address?.Trim(),
            postalCode?.Trim(),
            city?.Trim(),
            country,
            email?.Trim(),
            phone?.Trim(),
            paymentTermsDays,
            defaultRevenueAccountId));
    }

    public void Deactivate()
    {
        EnsureCanModify();

        if (!_isActive)
            throw new DomainException("CUSTOMER_ALREADY_INACTIVE",
                "Customer is already inactive",
                "Kunden er allerede inaktiv");

        Emit(new CustomerDeactivatedEvent());
    }

    public void Reactivate()
    {
        if (!_isCreated)
            throw new DomainException("CUSTOMER_NOT_FOUND",
                "Customer does not exist",
                "Kunden findes ikke");

        if (_isActive)
            throw new DomainException("CUSTOMER_ALREADY_ACTIVE",
                "Customer is already active",
                "Kunden er allerede aktiv");

        Emit(new CustomerReactivatedEvent());
    }

    private void EnsureCanModify()
    {
        if (!_isCreated)
            throw new DomainException("CUSTOMER_NOT_FOUND",
                "Customer does not exist",
                "Kunden findes ikke");
    }
}
