package de.effigenix.domain.masterdata.article;

import de.effigenix.domain.masterdata.Unit;
import de.effigenix.shared.common.Money;
import de.effigenix.shared.common.Result;

import java.math.BigDecimal;

/**
 * Entity representing a sales unit within an Article.
 * Enforces Unit/PriceModel consistency:
 * PIECE_FIXED → FIXED; KG/HUNDRED_GRAM/PIECE_VARIABLE → WEIGHT_BASED
 */
public class SalesUnit {

    private final SalesUnitId id;
    private final Unit unit;
    private final PriceModel priceModel;
    private Money price;

    private SalesUnit(SalesUnitId id, Unit unit, PriceModel priceModel, Money price) {
        this.id = id;
        this.unit = unit;
        this.priceModel = priceModel;
        this.price = price;
    }

    public static Result<ArticleError, SalesUnit> create(Unit unit, PriceModel priceModel, Money price) {
        if (unit == null || priceModel == null) {
            return Result.failure(new ArticleError.InvalidPriceModelCombination(
                    "Unit and PriceModel must not be null"));
        }
        if (!isValidCombination(unit, priceModel)) {
            return Result.failure(new ArticleError.InvalidPriceModelCombination(
                    "Unit " + unit + " is not compatible with PriceModel " + priceModel));
        }
        if (price == null || price.amount().compareTo(BigDecimal.ZERO) <= 0) {
            return Result.failure(new ArticleError.InvalidPrice("Price must be positive"));
        }
        return Result.success(new SalesUnit(SalesUnitId.generate(), unit, priceModel, price));
    }

    public static SalesUnit reconstitute(SalesUnitId id, Unit unit, PriceModel priceModel, Money price) {
        return new SalesUnit(id, unit, priceModel, price);
    }

    public Result<ArticleError, Void> updatePrice(Money newPrice) {
        if (newPrice == null || newPrice.amount().compareTo(BigDecimal.ZERO) <= 0) {
            return Result.failure(new ArticleError.InvalidPrice("Price must be positive"));
        }
        this.price = newPrice;
        return Result.success(null);
    }

    private static boolean isValidCombination(Unit unit, PriceModel priceModel) {
        return switch (unit) {
            case PIECE_FIXED -> priceModel == PriceModel.FIXED;
            case KG, HUNDRED_GRAM, PIECE_VARIABLE -> priceModel == PriceModel.WEIGHT_BASED;
        };
    }

    public SalesUnitId id() { return id; }
    public Unit unit() { return unit; }
    public PriceModel priceModel() { return priceModel; }
    public Money price() { return price; }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (!(obj instanceof SalesUnit other)) return false;
        return id.equals(other.id);
    }

    @Override
    public int hashCode() {
        return id.hashCode();
    }
}
