package de.effigenix.domain.inventory;

import de.effigenix.domain.masterdata.article.ArticleId;
import de.effigenix.shared.common.Result;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Domain Service: Erzeugt ADJUSTMENT-StockMovementDrafts für Inventur-Abweichungen.
 *
 * Für jedes CountItem mit Abweichung (actual ≠ expected) wird ein StockMovementDraft erzeugt:
 * - Positive Abweichung (Ist > Soll) → Direction IN
 * - Negative Abweichung (Ist < Soll) → Direction OUT
 *
 * Wählt die erste verfügbare Charge des jeweiligen Stocks als Buchungsziel.
 */
public class InventoryCountReconciliationService {

    public Result<InventoryCountError, List<StockMovementDraft>> reconcile(
            InventoryCount count,
            List<Stock> stocks,
            String performedBy
    ) {
        Map<ArticleId, Stock> stocksByArticle = stocks.stream()
                .collect(Collectors.toMap(Stock::articleId, s -> s, (a, b) -> a));

        List<StockMovementDraft> drafts = new ArrayList<>();

        for (CountItem item : count.countItems()) {
            BigDecimal deviation = item.deviation();
            if (deviation == null || deviation.compareTo(BigDecimal.ZERO) == 0) {
                continue;
            }

            Stock stock = stocksByArticle.get(item.articleId());
            if (stock == null || stock.batches().isEmpty()) {
                return Result.failure(new InventoryCountError.StockNotFoundForArticle(item.articleId().value()));
            }

            StockBatch batch = stock.batches().getFirst();

            String direction = deviation.compareTo(BigDecimal.ZERO) > 0 ? "IN" : "OUT";
            BigDecimal absAmount = deviation.abs();

            drafts.add(new StockMovementDraft(
                    stock.id().value(),
                    item.articleId().value(),
                    batch.id().value(),
                    batch.batchReference().batchId(),
                    batch.batchReference().batchType().name(),
                    "ADJUSTMENT",
                    direction,
                    absAmount.toPlainString(),
                    item.expectedQuantity().uom().name(),
                    "Inventur-Ausgleich: Inventur " + count.id().value(),
                    null,
                    performedBy
            ));
        }

        return Result.success(drafts);
    }
}
