package de.effigenix.infrastructure.masterdata.persistence.mapper;

import de.effigenix.domain.masterdata.*;
import de.effigenix.infrastructure.masterdata.persistence.entity.*;
import de.effigenix.shared.common.Address;
import de.effigenix.shared.common.ContactInfo;
import de.effigenix.shared.common.Money;
import de.effigenix.shared.common.PaymentTerms;
import org.springframework.stereotype.Component;

import java.util.Currency;
import java.util.List;
import java.util.stream.Collectors;

@Component
public class CustomerMapper {

    public CustomerEntity toEntity(Customer customer) {
        var entity = new CustomerEntity();
        entity.setId(customer.id().value());
        entity.setName(customer.name().value());
        entity.setType(customer.type().name());

        var contact = customer.contactInfo();
        if (contact != null) {
            entity.setPhone(contact.phone());
            entity.setEmail(contact.email());
            entity.setContactPerson(contact.contactPerson());
        }

        var billing = customer.billingAddress();
        entity.setBillingStreet(billing.street());
        entity.setBillingHouseNumber(billing.houseNumber());
        entity.setBillingPostalCode(billing.postalCode());
        entity.setBillingCity(billing.city());
        entity.setBillingCountry(billing.country());

        var terms = customer.paymentTerms();
        if (terms != null) {
            entity.setPaymentDueDays(terms.paymentDueDays());
            entity.setPaymentDescription(terms.description());
        }

        entity.setStatus(customer.status().name());
        entity.setCreatedAt(customer.createdAt());
        entity.setUpdatedAt(customer.updatedAt());

        entity.setDeliveryAddresses(customer.deliveryAddresses().stream()
                .map(da -> new DeliveryAddressEmbeddable(
                        da.label(),
                        da.address().street(), da.address().houseNumber(),
                        da.address().postalCode(), da.address().city(), da.address().country(),
                        da.contactPerson(), da.deliveryNotes()))
                .collect(Collectors.toList()));

        entity.setPreferences(customer.preferences());

        // FrameContract is saved separately — not via the @OneToOne mapping
        // (handled in JpaCustomerRepository)

        return entity;
    }

    public Customer toDomain(CustomerEntity entity, FrameContractEntity fcEntity) {
        Address billingAddress = new Address(
                entity.getBillingStreet(), entity.getBillingHouseNumber(),
                entity.getBillingPostalCode(), entity.getBillingCity(), entity.getBillingCountry()
        );

        ContactInfo contactInfo = new ContactInfo(
                entity.getPhone(), entity.getEmail(), entity.getContactPerson()
        );

        PaymentTerms paymentTerms = null;
        if (entity.getPaymentDueDays() != null) {
            paymentTerms = new PaymentTerms(entity.getPaymentDueDays(), entity.getPaymentDescription());
        }

        List<DeliveryAddress> deliveryAddresses = entity.getDeliveryAddresses().stream()
                .map(da -> new DeliveryAddress(
                        da.getLabel(),
                        new Address(da.getStreet(), da.getHouseNumber(),
                                da.getPostalCode(), da.getCity(), da.getCountry()),
                        da.getContactPerson(), da.getDeliveryNotes()))
                .collect(Collectors.toList());

        FrameContract frameContract = null;
        if (fcEntity != null) {
            List<ContractLineItem> lineItems = fcEntity.getLineItems().stream()
                    .map(li -> new ContractLineItem(
                            ArticleId.of(li.getArticleId()),
                            new Money(li.getAgreedPriceAmount(), Currency.getInstance(li.getAgreedPriceCurrency())),
                            li.getAgreedQuantity(),
                            li.getUnit() != null ? Unit.valueOf(li.getUnit()) : null))
                    .collect(Collectors.toList());

            frameContract = FrameContract.reconstitute(
                    FrameContractId.of(fcEntity.getId()),
                    fcEntity.getValidFrom(),
                    fcEntity.getValidUntil(),
                    DeliveryRhythm.valueOf(fcEntity.getDeliveryRhythm()),
                    lineItems
            );
        }

        return Customer.reconstitute(
                CustomerId.of(entity.getId()),
                new CustomerName(entity.getName()),
                CustomerType.valueOf(entity.getType()),
                billingAddress,
                contactInfo,
                paymentTerms,
                deliveryAddresses,
                frameContract,
                entity.getPreferences(),
                CustomerStatus.valueOf(entity.getStatus()),
                entity.getCreatedAt(),
                entity.getUpdatedAt()
        );
    }

    public FrameContractEntity toFrameContractEntity(FrameContract fc, String customerId) {
        var entity = new FrameContractEntity(
                fc.id().value(), customerId,
                fc.validFrom(), fc.validUntil(),
                fc.deliveryRhythm().name()
        );
        entity.setLineItems(fc.lineItems().stream()
                .map(li -> new ContractLineItemEmbeddable(
                        li.articleId().value(),
                        li.agreedPrice().amount(),
                        li.agreedPrice().currency().getCurrencyCode(),
                        li.agreedQuantity(),
                        li.unit() != null ? li.unit().name() : null))
                .collect(Collectors.toList()));
        return entity;
    }
}
