/** @license MIT | @cube-dev/ui-kit v0.0.0-canary-af8d194 | Cube Dev Team */
import { Lru } from "../parser/lru.js";

//#region src/tasty/plugins/okhsl-plugin.ts
/**
* OKHSL Plugin for Tasty
*
* Converts OKHSL color syntax to RGB notation.
* Supports angle units: deg, turn, rad, or unitless (degrees).
*
* Examples:
*   okhsl(240.5 50% 50%)
*   okhsl(240.5deg 50% 50%)
*   okhsl(0.25turn 50% 50%)
*   okhsl(1.57rad 50% 50%)
*
* Conversion math inlined from @texel/color to avoid external dependencies.
*/
const conversionCache = new Lru(500);
const OKLab_to_LMS_M = [
	[
		1,
		.3963377773761749,
		.2158037573099136
	],
	[
		1,
		-.1055613458156586,
		-.0638541728258133
	],
	[
		1,
		-.0894841775298119,
		-1.2914855480194092
	]
];
const LMS_to_linear_sRGB_M = [
	[
		4.076741636075959,
		-3.307711539258062,
		.2309699031821041
	],
	[
		-1.2684379732850313,
		2.6097573492876878,
		-.3413193760026569
	],
	[
		-.004196076138675526,
		-.703418617935936,
		1.7076146940746113
	]
];
const OKLab_to_linear_sRGB_coefficients = [
	[[-1.8817030993265873, -.8093650129914302], [
		1.19086277,
		1.76576728,
		.59662641,
		.75515197,
		.56771245
	]],
	[[1.8144407988010998, -1.194452667805235], [
		.73956515,
		-.45954404,
		.08285427,
		.12541073,
		-.14503204
	]],
	[[.13110757611180954, 1.813339709266608], [
		1.35733652,
		-.00915799,
		-1.1513021,
		-.50559606,
		.00692167
	]]
];
const TAU = 2 * Math.PI;
const clamp = (value, min, max) => Math.max(Math.min(value, max), min);
const constrainAngle = (angle) => (angle % 360 + 360) % 360;
const sRGBLinearToGamma = (val) => {
	const sign = val < 0 ? -1 : 1;
	const abs = Math.abs(val);
	return abs > .0031308 ? sign * (1.055 * Math.pow(abs, 1 / 2.4) - .055) : 12.92 * val;
};
const dot3 = (a, b) => a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
const transform = (input, matrix) => [
	dot3(input, matrix[0]),
	dot3(input, matrix[1]),
	dot3(input, matrix[2])
];
const cubed3 = (lms) => [
	lms[0] * lms[0] * lms[0],
	lms[1] * lms[1] * lms[1],
	lms[2] * lms[2] * lms[2]
];
const OKLabToLinearSRGB = (lab) => {
	return transform(cubed3(transform(lab, OKLab_to_LMS_M)), LMS_to_linear_sRGB_M);
};
const K1 = .206;
const K2 = .03;
const K3 = (1 + K1) / (1 + K2);
const toeInv = (x) => (x ** 2 + K1 * x) / (K3 * (x + K2));
const dotXY = (a, b) => a[0] * b[0] + a[1] * b[1];
const computeMaxSaturationOKLC = (a, b) => {
	const okCoeff = OKLab_to_linear_sRGB_coefficients;
	const lmsToRgb = LMS_to_linear_sRGB_M;
	const tmp2 = [a, b];
	const tmp3 = [
		0,
		a,
		b
	];
	let chnlCoeff;
	let chnlLMS;
	if (dotXY(okCoeff[0][0], tmp2) > 1) {
		chnlCoeff = okCoeff[0][1];
		chnlLMS = lmsToRgb[0];
	} else if (dotXY(okCoeff[1][0], tmp2) > 1) {
		chnlCoeff = okCoeff[1][1];
		chnlLMS = lmsToRgb[1];
	} else {
		chnlCoeff = okCoeff[2][1];
		chnlLMS = lmsToRgb[2];
	}
	const [k0, k1, k2, k3, k4] = chnlCoeff;
	const [wl, wm, ws] = chnlLMS;
	let sat = k0 + k1 * a + k2 * b + k3 * (a * a) + k4 * a * b;
	const dotYZ = (mat, vec) => mat[1] * vec[1] + mat[2] * vec[2];
	const kl = dotYZ(OKLab_to_LMS_M[0], tmp3);
	const km = dotYZ(OKLab_to_LMS_M[1], tmp3);
	const ks = dotYZ(OKLab_to_LMS_M[2], tmp3);
	let l_ = 1 + sat * kl;
	let m_ = 1 + sat * km;
	let s_ = 1 + sat * ks;
	const l = l_ * l_ * l_;
	const m = m_ * m_ * m_;
	const s = s_ * s_ * s_;
	const lds = 3 * kl * (l_ * l_);
	const mds = 3 * km * (m_ * m_);
	const sds = 3 * ks * (s_ * s_);
	const lds2 = 6 * (kl * kl) * l_;
	const mds2 = 6 * (km * km) * m_;
	const sds2 = 6 * (ks * ks) * s_;
	const f = wl * l + wm * m + ws * s;
	const f1 = wl * lds + wm * mds + ws * sds;
	const f2 = wl * lds2 + wm * mds2 + ws * sds2;
	sat = sat - f * f1 / (f1 * f1 - .5 * f * f2);
	return sat;
};
const findCuspOKLCH = (a, b) => {
	const S_cusp = computeMaxSaturationOKLC(a, b);
	const rgb_at_max = OKLabToLinearSRGB([
		1,
		S_cusp * a,
		S_cusp * b
	]);
	const L_cusp = Math.cbrt(1 / Math.max(Math.max(rgb_at_max[0], rgb_at_max[1]), Math.max(rgb_at_max[2], 0)));
	return [L_cusp, L_cusp * S_cusp];
};
const findGamutIntersectionOKLCH = (a, b, l1, c1, l0, cusp) => {
	const lmsToRgb = LMS_to_linear_sRGB_M;
	const tmp3 = [
		0,
		a,
		b
	];
	const floatMax = Number.MAX_VALUE;
	let t;
	const dotYZ = (mat, vec) => mat[1] * vec[1] + mat[2] * vec[2];
	const dotXYZ = (vec, x, y, z) => vec[0] * x + vec[1] * y + vec[2] * z;
	if ((l1 - l0) * cusp[1] - (cusp[0] - l0) * c1 <= 0) {
		const denom = c1 * cusp[0] + cusp[1] * (l0 - l1);
		t = denom === 0 ? 0 : cusp[1] * l0 / denom;
	} else {
		const denom = c1 * (cusp[0] - 1) + cusp[1] * (l0 - l1);
		t = denom === 0 ? 0 : cusp[1] * (l0 - 1) / denom;
		const dl = l1 - l0;
		const dc = c1;
		const kl = dotYZ(OKLab_to_LMS_M[0], tmp3);
		const km = dotYZ(OKLab_to_LMS_M[1], tmp3);
		const ks = dotYZ(OKLab_to_LMS_M[2], tmp3);
		const ldt_ = dl + dc * kl;
		const mdt_ = dl + dc * km;
		const sdt_ = dl + dc * ks;
		const L = l0 * (1 - t) + t * l1;
		const C = t * c1;
		const l_ = L + C * kl;
		const m_ = L + C * km;
		const s_ = L + C * ks;
		const l = l_ * l_ * l_;
		const m = m_ * m_ * m_;
		const s = s_ * s_ * s_;
		const ldt = 3 * ldt_ * l_ * l_;
		const mdt = 3 * mdt_ * m_ * m_;
		const sdt = 3 * sdt_ * s_ * s_;
		const ldt2 = 6 * ldt_ * ldt_ * l_;
		const mdt2 = 6 * mdt_ * mdt_ * m_;
		const sdt2 = 6 * sdt_ * sdt_ * s_;
		const r_ = dotXYZ(lmsToRgb[0], l, m, s) - 1;
		const r1 = dotXYZ(lmsToRgb[0], ldt, mdt, sdt);
		const r2 = dotXYZ(lmsToRgb[0], ldt2, mdt2, sdt2);
		const ur = r1 / (r1 * r1 - .5 * r_ * r2);
		let tr = -r_ * ur;
		const g_ = dotXYZ(lmsToRgb[1], l, m, s) - 1;
		const g1 = dotXYZ(lmsToRgb[1], ldt, mdt, sdt);
		const g2 = dotXYZ(lmsToRgb[1], ldt2, mdt2, sdt2);
		const ug = g1 / (g1 * g1 - .5 * g_ * g2);
		let tg = -g_ * ug;
		const b_ = dotXYZ(lmsToRgb[2], l, m, s) - 1;
		const b1 = dotXYZ(lmsToRgb[2], ldt, mdt, sdt);
		const b2 = dotXYZ(lmsToRgb[2], ldt2, mdt2, sdt2);
		const ub = b1 / (b1 * b1 - .5 * b_ * b2);
		let tb = -b_ * ub;
		tr = ur >= 0 ? tr : floatMax;
		tg = ug >= 0 ? tg : floatMax;
		tb = ub >= 0 ? tb : floatMax;
		t += Math.min(tr, Math.min(tg, tb));
	}
	return t;
};
const computeSt = (cusp) => {
	const l = cusp[0];
	const c = cusp[1];
	return [c / l, c / (1 - l)];
};
const computeStMid = (a, b) => {
	return [.11516993 + 1 / (7.4477897 + 4.1590124 * b + a * (-2.19557347 + 1.75198401 * b + a * (-2.13704948 - 10.02301043 * b + a * (-4.24894561 + 5.38770819 * b + 4.69891013 * a)))), .11239642 + 1 / (1.6132032 - .68124379 * b + a * (.40370612 + .90148123 * b + a * (-.27087943 + .6122399 * b + a * (.00299215 - .45399568 * b - .14661872 * a))))];
};
const getCs = (L, a, b, cusp) => {
	const cMax = findGamutIntersectionOKLCH(a, b, L, 1, L, cusp);
	const stMax = computeSt(cusp);
	const k = cMax / Math.min(L * stMax[0], (1 - L) * stMax[1]);
	const stMid = computeStMid(a, b);
	let ca = L * stMid[0];
	let cb = (1 - L) * stMid[1];
	const cMid = .9 * k * Math.sqrt(Math.sqrt(1 / (1 / ca ** 4 + 1 / cb ** 4)));
	ca = L * .4;
	cb = (1 - L) * .8;
	return [
		Math.sqrt(1 / (1 / ca ** 2 + 1 / cb ** 2)),
		cMid,
		cMax
	];
};
const OKHSLToOKLab = (hsl) => {
	let h = hsl[0];
	const s = hsl[1];
	const l = hsl[2];
	let L = toeInv(l);
	let a = 0;
	let b = 0;
	h = constrainAngle(h) / 360;
	if (L !== 0 && L !== 1 && s !== 0) {
		const a_ = Math.cos(TAU * h);
		const b_ = Math.sin(TAU * h);
		const [c0, cMid, cMax] = getCs(L, a_, b_, findCuspOKLCH(a_, b_));
		const mid = .8;
		const midInv = 1.25;
		let t, k0, k1, k2;
		if (s < mid) {
			t = midInv * s;
			k0 = 0;
			k1 = mid * c0;
			k2 = 1 - k1 / cMid;
		} else {
			t = 5 * (s - .8);
			k0 = cMid;
			k1 = .2 * cMid ** 2 * 1.25 ** 2 / c0;
			k2 = 1 - k1 / (cMax - cMid);
		}
		const c = k0 + t * k1 / (1 - k2 * t);
		a = c * a_;
		b = c * b_;
	}
	return [
		L,
		a,
		b
	];
};
const okhslToSRGB = (h, s, l) => {
	const linearRGB = OKLabToLinearSRGB(OKHSLToOKLab([
		h,
		s,
		l
	]));
	return [
		clamp(sRGBLinearToGamma(linearRGB[0]), 0, 1),
		clamp(sRGBLinearToGamma(linearRGB[1]), 0, 1),
		clamp(sRGBLinearToGamma(linearRGB[2]), 0, 1)
	];
};
/**
* Parse an angle value with optional unit.
* Supports: deg, turn, rad, or unitless (treated as degrees).
*/
const parseAngle = (value) => {
	const match = value.match(/^([+-]?\d*\.?\d+)(deg|turn|rad)?$/);
	if (!match) return 0;
	const num = parseFloat(match[1]);
	switch (match[2]) {
		case "turn": return num * 360;
		case "rad": return num * 180 / Math.PI;
		default: return num;
	}
};
/**
* Parse a percentage value (e.g., "50%") to a 0-1 range.
*/
const parsePercentage = (value) => {
	const match = value.match(/^([+-]?\d*\.?\d+)%?$/);
	if (!match) return 0;
	const num = parseFloat(match[1]);
	return value.includes("%") ? num / 100 : num;
};
/**
* The okhsl function handler for tasty parser.
* Receives parsed style groups and returns an RGB color string.
*/
const okhslFunc = (groups) => {
	if (groups.length === 0 || groups[0].all.length < 3) {
		console.warn("[okhsl] Expected 3 values (H S L), got:", groups);
		return "rgb(0% 0% 0%)";
	}
	const tokens = groups[0].all;
	const cacheKey = tokens.slice(0, 3).join(" ");
	const cached = conversionCache.get(cacheKey);
	if (cached) return cached;
	const h = parseAngle(tokens[0]);
	const s = parsePercentage(tokens[1]);
	const l = parsePercentage(tokens[2]);
	const [r, g, b] = okhslToSRGB(h, clamp(s, 0, 1), clamp(l, 0, 1));
	const format = (n) => {
		const pct = n * 100;
		return parseFloat(pct.toFixed(1)).toString() + "%";
	};
	const result = `rgb(${format(r)} ${format(g)} ${format(b)})`;
	conversionCache.set(cacheKey, result);
	return result;
};
/**
* OKHSL Plugin for Tasty.
*
* Adds support for the `okhsl()` color function in tasty styles.
*
* @example
* ```ts
* import { configure } from '@cube-dev/ui-kit';
* import { okhslPlugin } from '@cube-dev/ui-kit/tasty/plugins';
*
* configure({
*   plugins: [okhslPlugin()],
* });
*
* // Now you can use okhsl in styles:
* const Box = tasty({
*   styles: {
*     fill: 'okhsl(240 50% 50%)',
*   },
* });
* ```
*/
const okhslPlugin = () => ({
	name: "okhsl",
	funcs: { okhsl: okhslFunc }
});

//#endregion
export { okhslFunc, okhslPlugin };
//# sourceMappingURL=okhsl-plugin.js.map