package de.effigenix.domain.production;

import de.effigenix.shared.common.QuantityError;
import de.effigenix.shared.common.Result;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.regex.Pattern;

/**
 * Value Object representing a production batch number.
 *
 * <p>Format: {@code P-YYYY-MM-DD-XXX} where XXX is a 3-digit sequence number (001–999).
 *
 * <p>Invariant: must match the pattern P-YYYY-MM-DD-XXX
 */
public record BatchNumber(String value) {

    private static final Pattern FORMAT = Pattern.compile("^P-\\d{4}-\\d{2}-\\d{2}-\\d{3}$");
    private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    public BatchNumber {
        if (value == null || !FORMAT.matcher(value).matches()) {
            throw new IllegalArgumentException(
                    "Batch number must match format P-YYYY-MM-DD-XXX, was: " + value);
        }
    }

    /**
     * Creates a BatchNumber, returning a Result.
     */
    public static Result<QuantityError, BatchNumber> of(String value) {
        if (value == null || !FORMAT.matcher(value).matches()) {
            return Result.failure(new QuantityError.InvalidBatchNumber(value));
        }
        return Result.success(new BatchNumber(value));
    }

    /**
     * Generates a new BatchNumber for the given date and sequence number.
     */
    public static BatchNumber generate(LocalDate date, int sequenceNumber) {
        if (sequenceNumber < 1 || sequenceNumber > 999) {
            throw new IllegalArgumentException(
                    "Sequence number must be between 1 and 999, was: " + sequenceNumber);
        }
        String formatted = String.format("P-%s-%03d", date.format(DATE_FORMAT), sequenceNumber);
        return new BatchNumber(formatted);
    }

    /**
     * Extracts the date portion from the batch number.
     */
    public LocalDate date() {
        String datePart = value.substring(2, 12);
        return LocalDate.parse(datePart, DATE_FORMAT);
    }

    /**
     * Extracts the sequence number from the batch number.
     */
    public int sequenceNumber() {
        return Integer.parseInt(value.substring(13));
    }
}
