//#region src/rates-table/dataset.ts
/**
* Israel VAT rate history — byte-faithful `IL_VAT_RATES` seed.
* Sources: Israeli Tax Authority historical records.
*/
const IL_VAT_SCHEDULE = [
	{
		effectiveFrom: "1976-07-01",
		value: "0.0800",
		unit: "fraction"
	},
	{
		effectiveFrom: "1977-11-01",
		value: "0.1200",
		unit: "fraction"
	},
	{
		effectiveFrom: "1982-08-01",
		value: "0.1500",
		unit: "fraction"
	},
	{
		effectiveFrom: "1985-06-01",
		value: "0.1700",
		unit: "fraction"
	},
	{
		effectiveFrom: "1985-10-01",
		value: "0.1500",
		unit: "fraction"
	},
	{
		effectiveFrom: "1990-03-01",
		value: "0.1600",
		unit: "fraction"
	},
	{
		effectiveFrom: "1991-01-01",
		value: "0.1800",
		unit: "fraction"
	},
	{
		effectiveFrom: "1993-01-01",
		value: "0.1700",
		unit: "fraction"
	},
	{
		effectiveFrom: "2002-06-15",
		value: "0.1800",
		unit: "fraction"
	},
	{
		effectiveFrom: "2004-03-01",
		value: "0.1700",
		unit: "fraction"
	},
	{
		effectiveFrom: "2005-09-01",
		value: "0.1650",
		unit: "fraction"
	},
	{
		effectiveFrom: "2006-07-01",
		value: "0.1550",
		unit: "fraction"
	},
	{
		effectiveFrom: "2009-07-01",
		value: "0.1650",
		unit: "fraction"
	},
	{
		effectiveFrom: "2010-01-01",
		value: "0.1600",
		unit: "fraction"
	},
	{
		effectiveFrom: "2012-09-01",
		value: "0.1700",
		unit: "fraction"
	},
	{
		effectiveFrom: "2013-06-02",
		value: "0.1800",
		unit: "fraction"
	},
	{
		effectiveFrom: "2015-10-01",
		value: "0.1700",
		unit: "fraction"
	},
	{
		effectiveFrom: "2025-01-01",
		value: "0.1800",
		unit: "fraction"
	}
];
/** EU per-country standard-rate schedules — scaffold; extend with full matrix over time. */
const EU_VAT_SCHEDULES = {
	DE: [{
		effectiveFrom: "2007-01-01",
		value: 19,
		unit: "percent"
	}],
	FR: [{
		effectiveFrom: "2014-01-01",
		value: 20,
		unit: "percent"
	}]
};
/**
* EU reduced-rate category matrix — structure scaffold only.
* Keys = category id; values = per-country rate in **basis points** (host resolves
* category). Basis points (not percent) so non-integer reduced rates — e.g. FR 5.5%
* = 550 bp — are represented losslessly; a float `5.5` would break the integer-only
* `percent`/`basisPoints` normalizers (`BigInt(5.5)` throws).
*/
const EU_REDUCED_RATE_MATRIX = {
	food: {
		DE: 700,
		FR: 550
	},
	books: {
		DE: 700,
		FR: 550
	}
};
//#endregion
//#region src/rates-table/resolve.ts
const TEN_THOUSAND$1 = 10000n;
/** A rate value failed the basis-points trust-boundary contract (integer, ≥ 0). */
var InvalidVatRateError = class extends Error {
	value;
	constructor(message, value) {
		super(message);
		this.name = "InvalidVatRateError";
		this.value = String(value);
	}
};
/**
* Coerce to an exact non-negative integer bigint, or throw `InvalidVatRateError`.
* The single chokepoint every rate funnels through (`from*` + `resolveVatRate`),
* so a negative or fractional rate can never reach the BigInt money path —
* negative inputs fall outside the spec's non-negative domain (trunc≠floor
* mis-rounding; a negative bp also breaks `extractVat`'s `10000 + bp` denominator).
*/
function toBasisPointsBigInt(bp) {
	let n;
	if (typeof bp === "number") {
		if (!Number.isInteger(bp)) throw new InvalidVatRateError(`VAT basis points must be an integer, got ${bp}`, bp);
		n = BigInt(bp);
	} else n = bp;
	if (n < 0n) throw new InvalidVatRateError(`VAT rate must be non-negative, got ${n} bp`, n);
	return n;
}
function fromBasisPoints(bp) {
	return toBasisPointsBigInt(bp);
}
function fromPercent(pct) {
	if (typeof pct === "number" && !Number.isInteger(pct)) throw new InvalidVatRateError(`VAT percent must be an integer, got ${pct}`, pct);
	return fromBasisPoints(BigInt(pct) * 100n);
}
/** `frac` is a decimal fraction string or number (e.g. `0.1700` → 1700 bp). */
function fromFraction(frac) {
	return fromBasisPoints(fractionToBasisPoints(frac));
}
/**
* A `date` argument failed the `YYYY-MM-DD` trust-boundary contract.
* Validated by shape only (no `Date` construction — that would reintroduce the
* UTC-guess timezone pitfall the string contract exists to remove).
*/
var InvalidVatDateError = class extends Error {
	value;
	constructor(message, value) {
		super(message);
		this.name = "InvalidVatDateError";
		this.value = String(value);
	}
};
var NoRateForDateError = class extends Error {
	date;
	firstEffectiveFrom;
	constructor(date, firstEffectiveFrom) {
		super(firstEffectiveFrom ? `No VAT rate for date ${date} (before first entry ${firstEffectiveFrom})` : `No VAT rate for date ${date}`);
		this.name = "NoRateForDateError";
		this.date = date;
		this.firstEffectiveFrom = firstEffectiveFrom;
	}
};
function fractionToBasisPoints(frac) {
	const s = String(frac);
	if (!/^-?\d*(\.\d+)?$/.test(s) || s === "" || s === "-" || s === ".") throw new InvalidVatRateError(`VAT fraction is not a decimal number: ${s}`, frac);
	const negative = s.startsWith("-");
	const [whole, fracPart = ""] = (negative ? s.slice(1) : s).split(".");
	if (/[1-9]/.test(fracPart.slice(4))) throw new InvalidVatRateError(`VAT fraction has sub-basis-point precision (max 4 decimals): ${s}`, frac);
	const padded = (fracPart + "0000").slice(0, 4);
	const bp = BigInt(whole || "0") * TEN_THOUSAND$1 + BigInt(padded || "0");
	return negative ? -bp : bp;
}
function normalizeToBasisPoints(value, unit) {
	switch (unit) {
		case "basisPoints":
			if (typeof value === "number") return toBasisPointsBigInt(value);
			if (!/^-?\d+$/.test(value.trim())) throw new InvalidVatRateError(`VAT basis points must be an integer string, got ${value}`, value);
			return toBasisPointsBigInt(BigInt(value.trim()));
		case "percent": {
			const pct = typeof value === "number" ? value : Number(value);
			if (!Number.isInteger(pct)) throw new InvalidVatRateError(`VAT percent must be an integer, got ${value}`, value);
			return toBasisPointsBigInt(pct) * 100n;
		}
		case "fraction": return toBasisPointsBigInt(fractionToBasisPoints(value));
	}
}
/** A well-formed `YYYY-MM-DD` calendar date (shape-checked, not TZ-resolved). */
const YYYY_MM_DD = /^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/;
/**
* Last schedule entry with `effectiveFrom ≤ date` (most-recent-on-or-before).
*
* `date` is a **host-resolved `YYYY-MM-DD` legal date string** — never a JS
* `Date`. A `Date` is an instant that only becomes a calendar day *through* a
* timezone, and this module is country-neutral so it cannot know the legal
* timezone; the host owns that resolution (see spec Money-math § date-contract).
* Malformed input throws `InvalidVatDateError` (trust boundary). Throws
* `NoRateForDateError` when the date precedes every entry.
*/
function resolveVatRate(schedule, date) {
	if (!YYYY_MM_DD.test(date)) throw new InvalidVatDateError(`VAT date must be a host-resolved YYYY-MM-DD string, got ${JSON.stringify(date)}`, date);
	const sorted = [...schedule].sort((a, b) => a.effectiveFrom.localeCompare(b.effectiveFrom));
	let match;
	for (const entry of sorted) if (entry.effectiveFrom <= date) match = entry;
	else break;
	if (!match) throw new NoRateForDateError(date, sorted[0]?.effectiveFrom);
	return fromBasisPoints(normalizeToBasisPoints(match.value, match.unit));
}
//#endregion
//#region src/rates-table/vat-math.ts
const TEN_THOUSAND = 10000n;
/** A money amount failed the non-negative-agorot trust-boundary contract. */
var InvalidAmountError = class extends Error {
	amount;
	constructor(label, amount) {
		super(`${label} must be a non-negative integer agorot amount, got ${amount}`);
		this.name = "InvalidAmountError";
		this.amount = String(amount);
	}
};
/**
* Round-half-up via `floor((2a + b) / (2b))` — exact for any positive denominator.
* Correct only for a NON-NEGATIVE numerator: BigInt `/` truncates toward zero, so
* a negative numerator would diverge from `floor` (off-by-one wrong money). Callers
* guard amount ≥ 0 and the rate brand guarantees bp ≥ 0, so `a ≥ 0` always holds.
*/
function roundHalfUp(numerator, denominator) {
	return (2n * numerator + denominator) / (2n * denominator);
}
/** Exclusive: VAT added to net; `gross = net + vat`. */
function applyVat(netAgorot, rate) {
	if (netAgorot < 0n) throw new InvalidAmountError("netAgorot", netAgorot);
	const vat = roundHalfUp(netAgorot * rate, TEN_THOUSAND);
	return {
		vat,
		gross: netAgorot + vat
	};
}
/** Inclusive: VAT extracted from gross; `net = gross − vat`. */
function extractVat(grossAgorot, rate) {
	if (grossAgorot < 0n) throw new InvalidAmountError("grossAgorot", grossAgorot);
	const denominator = TEN_THOUSAND + rate;
	const vat = roundHalfUp(grossAgorot * rate, denominator);
	return {
		net: grossAgorot - vat,
		vat
	};
}
//#endregion
export { EU_REDUCED_RATE_MATRIX, EU_VAT_SCHEDULES, IL_VAT_SCHEDULE, InvalidAmountError, InvalidVatDateError, InvalidVatRateError, NoRateForDateError, applyVat, extractVat, fractionToBasisPoints, fromBasisPoints, fromFraction, fromPercent, normalizeToBasisPoints, resolveVatRate };
