import {
  getColors
} from "./chunk-4UWS5Y3N.js";
import {
  convertUnits,
  isNumeric,
  isStrictNumeric
} from "./chunk-JNITUVXP.js";
import {
  format
} from "./chunk-OAWQ6LOO.js";

// ../shared/utils/dist/src/termdb.bins.js
function validate_bins(binconfig) {
  const bc = binconfig;
  if (!bc || typeof bc !== "object") throw "bin schema must be an object";
  if (!("type" in bc)) bc.type = "regular-bin";
  if (bc.type == "custom-bin") {
    if (!Array.isArray(bc.lst)) throw "binconfig.lst must be an array";
    if (!bc.lst.length) throw "binconfig.lst must have entries";
    const first_bin = bc.lst[0];
    const last_bin = bc.lst[bc.lst.length - 1];
    for (const bin of bc.lst) {
      if (!("startinclusive" in bin) && !("stopinclusive" in bin)) {
        throw "custom bin.startinclusive and/or bin.stopinclusive must be defined";
      }
      if (bin == first_bin) {
        if ("startunbounded" in bin && !bin.startunbounded) {
          throw `a custom first bin must not set bin.startunbounded to false`;
        }
        bin.startunbounded = true;
        if ("start" in bin) {
          throw "a custom first bin must not set a bin.start value";
        }
        if ("start_percentile" in bin) {
          throw "the first bin must not set a bin.start_percentile value";
        }
        if (!("stop" in bin)) {
          throw `a custom first bin must define a bin.stop value`;
        }
        if (!isStrictNumeric(bin.stop)) {
          throw `a custom first bin.stop value should be numeric`;
        }
      } else if (bin == last_bin) {
        if (!("start" in bin)) {
          throw `a custom last bin must define a bin.start value`;
        }
        if (!isStrictNumeric(bin.start)) {
          throw `a custom last bin.start must be numeric`;
        }
        if ("stopunbounded" in bin && !bin.stopunbounded) {
          throw "a custom last bin must not set bin.stopunbounded to false";
        }
        bin.stopunbounded = true;
        if ("stop" in bin) {
          throw "a custom last bin must not set a bin.stop value";
        }
      } else {
        if (bin.startunbounded || bin.stopunbounded) {
          throw "bin.startunbounded and bin.stopunbounded must not be set for non-first/non-last bins";
        }
        if (!isStrictNumeric(bin.start)) throw "bin.start must be numeric for a non-first bin";
        if (!isStrictNumeric(bin.stop)) throw "bin.stop must be numeric for a non-last bin";
      }
    }
  } else if (bc.type == "regular-bin") {
    if (!Number.isFinite(bc.bin_size)) throw "non-numeric bin_size";
    if (bc.bin_size <= 0) throw "bin_size must be greater than 0";
    if (!bc.startinclusive && !bc.stopinclusive) {
      bc.startinclusive = 1;
      bc.stopinclusive = 0;
    }
    if (!bc.first_bin) throw "first_bin{} missing";
    if (typeof bc.first_bin != "object") throw "first_bin{} is not an object";
    if (!Object.keys(bc.first_bin).length) throw "first_bin is an empty object";
    {
      const b = bc.first_bin;
      b.startunbounded = true;
      if (b.stop_percentile) {
        if (!Number.isInteger(b.stop_percentile)) throw "first_bin.stop_percentile should be integer";
        if (b.stop_percentile <= 0 || b.stop_percentile >= 100) throw "first_bin.stop_percentile out of bound (0-100)";
      } else if (!Number.isFinite(b.stop)) {
        throw "first_bin.stop not a number when stop_percentile is not set";
      }
    }
    if (bc.last_bin) {
      const b = bc.last_bin;
      if (b.start_percentile) {
        if (!Number.isInteger(b.start_percentile)) throw "last_bin.start_percentile should be integer";
        if (b.start_percentile <= 0 || b.start_percentile >= 100) throw "last_bin.start_percentile out of bound (0-100)";
      } else if (!Number.isFinite(b.start)) {
        throw "last_bin.start not a number when start_percentile is not set";
      }
      b.stopunbounded = true;
      if ("stop" in b) {
        throw "a regular last bin must not set a bin.stop value";
      }
    }
  } else {
    throw `invalid binconfig.type="${bc.type}"`;
  }
}
var maxNumBins = 100;
function compute_bins(binconfig, summaryfxn, valueConversion) {
  const bc = binconfig;
  validate_bins(bc);
  if (bc.lst) {
    if (!Array.isArray(bc.lst)) throw `bc.lst is not an array`;
    if (bc.lst.length > maxNumBins) throw `bc.lst exceed the maximum of ${maxNumBins} allowed entries`;
    const k2c2 = getColors(bc.lst.length);
    for (const bin of bc.lst) bin.color = k2c2(bin.label);
  }
  if (bc.type == "custom-bin") return JSON.parse(JSON.stringify(bc.lst));
  if (typeof summaryfxn != "function") throw "summaryfxn required for modules/termdb.bins.js compute_bins()";
  const percentiles = target_percentiles(bc);
  const summary = summaryfxn(percentiles);
  if (!summary || typeof summary !== "object") throw "invalid returned value by summaryfxn";
  bc.results = { summary };
  if (!bc.binLabelFormatter) bc.binLabelFormatter = getNumDecimalsFormatter(bc);
  const minFloor = Math.floor(summary.min * 100) / 100;
  const maxCeil = Math.ceil(summary.max * 100) / 100;
  const min = bc.first_bin.startunbounded ? minFloor : bc.first_bin.start_percentile ? summary["p" + bc.first_bin.start_percentile] : bc.first_bin.start;
  let max = maxCeil, last_start, last_stop;
  if (bc.last_bin) {
    max = bc.last_bin.stopunbounded ? maxCeil : bc.last_bin.stop_percentile ? summary["p" + bc.last_bin.stop_percentile] : isNumeric(bc.last_bin.stop) && bc.last_bin.stop <= summary.max ? bc.last_bin.stop : maxCeil;
    last_start = isStrictNumeric(bc.last_bin.start_percentile) ? summary["p" + bc.last_bin.start_percentile] : isStrictNumeric(bc.last_bin.start) ? bc.last_bin.start : void 0;
    last_stop = bc.last_bin.stopunbounded ? null : bc.last_bin.stop_percentile ? summary["p" + bc.last_bin.stop_percentile] : isStrictNumeric(bc.last_bin.stop) ? bc.last_bin.stop : null;
  } else if (bc.lst) {
    const last_bin = bc.lst[bc.lst.length - 1];
    last_start = last_bin.start;
    last_stop = "stop" in last_bin && !last_bin.stopunbounded ? last_bin.stop : maxCeil;
    max = last_stop;
  } else {
    last_start = maxCeil;
    last_stop = maxCeil;
  }
  const numericMax = isStrictNumeric(max);
  const numericLastStart = isStrictNumeric(last_start);
  const numericLastStop = isStrictNumeric(last_stop);
  if (!numericMax && !numericLastStart) return [];
  const bins = [];
  let currBin = {
    startunbounded: bc.first_bin.startunbounded,
    start: bc.first_bin.startunbounded ? void 0 : min,
    stop: isStrictNumeric(bc.first_bin.stop_percentile) ? +summary["p" + bc.first_bin.stop_percentile] : isStrictNumeric(bc.first_bin.stop) ? +bc.first_bin.stop : min + bc.bin_size,
    startinclusive: bc.startinclusive,
    stopinclusive: bc.stopinclusive
  };
  if (!isStrictNumeric(currBin.stop)) throw "the computed first_bin.stop is non-numeric" + currBin.stop;
  while (numericMax && currBin.stop <= max || currBin.startunbounded && !bins.length || currBin.stopunbounded) {
    bins.push(currBin);
    if (currBin.stop >= max) {
      currBin.stopunbounded = true;
      if (bins.length > 1) {
        delete currBin.stop;
      }
    }
    currBin.label = get_bin_label(currBin, bc, valueConversion);
    if (currBin.stopunbounded) break;
    const upper = currBin.stop + bc.bin_size;
    const previousStop = currBin.stop;
    currBin = {
      startinclusive: bc.startinclusive,
      stopinclusive: bc.stopinclusive,
      start: previousStop,
      stop: numericLastStop && (previousStop == last_start || upper > last_stop) ? last_stop : numericLastStart && upper > last_start && previousStop != last_start ? last_start : upper
    };
    if (currBin.stop >= max) {
      currBin.stop = max;
      if (bc.last_bin && bc.last_bin.stopunbounded) currBin.stopunbounded = 1;
      if (bc.last_bin && bc.last_bin.stopinclusive) currBin.stopinclusive = 1;
    }
    if (numericLastStart && currBin.start == last_start) {
      if (bc.last_bin && bc.last_bin.stopunbounded) currBin.stopunbounded = 1;
    }
    if (currBin.start > currBin.stop) {
      if (numericLastStart && currBin.stop == last_start && bc.last_bin && bc.last_bin.stopunbounded)
        currBin.stopunbounded = true;
      else break;
    }
    if (bins.length + 1 >= maxNumBins) {
      delete currBin.stop;
      currBin.stopunbounded = true;
      currBin.label = get_bin_label(currBin, bc, valueConversion);
      if (!bins.includes(currBin)) bins.push(currBin);
      const hint = "Please increase the bin_size or first bin stop, or have a lower last bin start.";
      throw new Error(hint + " (max_num_bins_reached)");
    }
  }
  delete bc.binLabelFormatter;
  if (bins.length > 1) {
    delete bins[bins.length - 1].stop;
  }
  const k2c = getColors(bins.length);
  for (const bin of bins) bin.color = k2c(bin.label);
  return bins;
}
function getNumDecimalsFormatter(bc) {
  return "rounding" in bc ? format(bc.rounding) : (d) => d;
}
function get_bin_label(bin, binconfig, valueConversion) {
  if (!bin) return "missing bin.label";
  if (bin.label) return bin.label;
  const bc = binconfig;
  if (!bc.binLabelFormatter) bc.binLabelFormatter = getNumDecimalsFormatter(bc);
  if (!bin.startunbounded && !bin.stopunbounded && !("startinclusive" in bin) && !("stopinclusive" in bin)) {
    if (bc.startinclusive) bin.startinclusive = true;
    else if (bc.stopinclusive) bin.stopinclusive = true;
  }
  const start = bc.use_as == "bins" || bin.start;
  const stop = bc.use_as == "bins" || bin.stop;
  let label_offset = 0;
  if ("label_offset" in bc) {
    bc.label_offset_ignored = "bin_size" in bc && bc.bin_size < bc.label_offset;
    if (!bc.label_offset_ignored) label_offset = bc.label_offset;
  } else if (bc.bin_size === 1 && bc.termtype == "integer") {
    label_offset = 1;
  }
  if (bin.startunbounded) {
    const oper = bin.stopinclusive ? "\u2264" : "<";
    const v1 = valueConversion ? convertUnits(stop, valueConversion.fromUnit, valueConversion.toUnit, valueConversion.scaleFactor, true) : bc.binLabelFormatter(stop);
    return oper + v1;
  }
  if (bin.stopunbounded || start === stop) {
    const oper = bin.startinclusive ? "\u2265" : ">";
    const v0 = valueConversion ? convertUnits(start, valueConversion.fromUnit, valueConversion.toUnit, valueConversion.scaleFactor, true) : bc.binLabelFormatter(start);
    return oper + v0;
  }
  if (label_offset && bin.startinclusive && !bin.stopinclusive) {
    if (Number.isInteger(bc.bin_size) && Math.abs(start - stop) === label_offset) {
      return "" + (valueConversion ? convertUnits(start, valueConversion.fromUnit, valueConversion.toUnit, valueConversion.scaleFactor, true) : bc.binLabelFormatter(start));
    } else {
      const v0 = valueConversion ? convertUnits(start, valueConversion.fromUnit, valueConversion.toUnit, valueConversion.scaleFactor, true) : bc.binLabelFormatter(start);
      const v1 = valueConversion ? convertUnits(
        stop - label_offset,
        valueConversion.fromUnit,
        valueConversion.toUnit,
        valueConversion.scaleFactor,
        true
      ) : bc.binLabelFormatter(stop - label_offset);
      return +v0 >= +v1 ? v0.toString() : v0 + " to " + v1;
    }
  } else {
    const oper0 = bin.startinclusive ? "" : ">";
    const oper1 = bin.stopinclusive ? "" : "<";
    const v0 = valueConversion ? convertUnits(start, valueConversion.fromUnit, valueConversion.toUnit, valueConversion.scaleFactor, true) : Number.isInteger(start) ? start : bc.binLabelFormatter(start);
    const v1 = valueConversion ? convertUnits(stop, valueConversion.fromUnit, valueConversion.toUnit, valueConversion.scaleFactor, true) : Number.isInteger(stop) ? stop : bc.binLabelFormatter(stop);
    if (+v0 >= +v1) {
      const oper = bin.startinclusive ? "\u2265" : ">";
      return oper + v0;
    } else {
      return oper0 + v0 + " to " + oper1 + v1;
    }
  }
}
function get_bin_range_equation(bin, binconfig) {
  const x = '<span style="font-family:Times;font-style:italic;">x</span>';
  let range_eq;
  const copy = structuredClone(bin);
  copy.label = "";
  const bin_label = get_bin_label(copy, binconfig, void 0);
  if (bin.startunbounded || bin.stopunbounded) {
    range_eq = x + " " + bin_label;
  } else if (bin.startinclusive) {
    range_eq = bin_label.replace("to <", "\u2264 " + x + " <");
  } else if (bin.stopinclusive) {
    range_eq = bin_label.replace(">", "").replace("to", "< " + x + " \u2264");
  }
  return range_eq;
}
function target_percentiles(binconfig) {
  const percentiles = [];
  const f = binconfig.first_bin;
  if (f && isStrictNumeric(f.start_percentile)) percentiles.push(f.start_percentile);
  if (f && isStrictNumeric(f.stop_percentile)) percentiles.push(f.stop_percentile);
  const l = binconfig.last_bin;
  if (l && isStrictNumeric(l.start_percentile)) percentiles.push(l.start_percentile);
  if (l && isStrictNumeric(l.stop_percentile)) percentiles.push(l.stop_percentile);
  return percentiles;
}

export {
  compute_bins,
  get_bin_label,
  get_bin_range_equation
};
//# sourceMappingURL=chunk-QH6W3NVF.js.map
