package com.xfestudio.xfeservermanager.core.economy;

import java.time.Instant;
import java.util.Locale;
import java.util.Objects;
import java.util.UUID;

/** Revisioned definition of one server currency. Amounts are wire-safe decimal strings. */
public record CurrencyDefinition(
        UUID id,
        String code,
        String name,
        String symbol,
        String icon,
        int fractionDigits,
        String initialBalance,
        String minimumBalance,
        String maximumBalance,
        boolean playerTransferAllowed,
        boolean enabled,
        boolean primary,
        long revision,
        String createdBy,
        Instant createdAt,
        Instant updatedAt) {

    public CurrencyDefinition {
        Objects.requireNonNull(id, "id");
        code = Objects.toString(code, "").strip().toLowerCase(Locale.ROOT);
        if (!code.matches("[a-z][a-z0-9_]{0,31}")) {
            throw new IllegalArgumentException("currency code must be a lowercase identifier");
        }
        name = printable(name, "currency name", 1, 64);
        symbol = printable(symbol, "currency symbol", 1, 16);
        icon = Objects.toString(icon, "item:minecraft:emerald").strip().toLowerCase(Locale.ROOT);
        if (!icon.matches("(?:uploaded:[0-9a-f-]{36}|(?:item|block|texture):[a-z0-9_.-]+:[a-z0-9_./-]+)")) {
            throw new IllegalArgumentException("currency icon must reference an uploaded image, item, block, or texture");
        }
        long minimum = EconomyAmounts.parse(minimumBalance, fractionDigits, "minimumBalance");
        long initial = EconomyAmounts.parse(initialBalance, fractionDigits, "initialBalance");
        long maximum = EconomyAmounts.parse(maximumBalance, fractionDigits, "maximumBalance");
        if (minimum > initial || initial > maximum || minimum == maximum) {
            throw new IllegalArgumentException("currency balances must satisfy minimum <= initial <= maximum");
        }
        minimumBalance = EconomyAmounts.format(minimum, fractionDigits);
        initialBalance = EconomyAmounts.format(initial, fractionDigits);
        maximumBalance = EconomyAmounts.format(maximum, fractionDigits);
        if (primary && !enabled) throw new IllegalArgumentException("the primary currency must be enabled");
        if (revision < 0) throw new IllegalArgumentException("currency revision must not be negative");
        createdBy = printable(createdBy, "currency creator", 1, 128);
        Objects.requireNonNull(createdAt, "createdAt");
        Objects.requireNonNull(updatedAt, "updatedAt");
    }

    public long initialMinorUnits() {
        return EconomyAmounts.parse(initialBalance, fractionDigits, "initialBalance");
    }

    public long minimumMinorUnits() {
        return EconomyAmounts.parse(minimumBalance, fractionDigits, "minimumBalance");
    }

    public long maximumMinorUnits() {
        return EconomyAmounts.parse(maximumBalance, fractionDigits, "maximumBalance");
    }

    private static String printable(String value, String field, int minimum, int maximum) {
        String result = Objects.toString(value, "").strip();
        if (result.length() < minimum || result.length() > maximum
                || result.codePoints().anyMatch(Character::isISOControl)) {
            throw new IllegalArgumentException(field + " must contain " + minimum + "-" + maximum
                    + " printable characters");
        }
        return result;
    }
}
