import {
  getDefaultProfilePlotSettings,
  getProfilePlotConfig,
  makeChartBtnMenu,
  profilePlot
} from "./chunk-P3IENRWJ.js";
import {
  fillTwLst,
  renderTable
} from "./chunk-SA7APTJR.js";
import "./chunk-HJ6L54YS.js";
import "./chunk-LSEFWW72.js";
import "./chunk-SKREEF3H.js";
import "./chunk-HYOEWQ5P.js";
import "./chunk-HBW42TDT.js";
import "./chunk-G6O3URDN.js";
import "./chunk-FN5XPUPH.js";
import "./chunk-IIT367QZ.js";
import "./chunk-RZGEKL77.js";
import "./chunk-UI7OCM2A.js";
import "./chunk-YZK37YCC.js";
import {
  dofetch3
} from "./chunk-7EMWHCVW.js";
import "./chunk-7IYJZZQI.js";
import {
  copyMerge,
  getCompInit
} from "./chunk-M3J4MINX.js";
import "./chunk-PF4DSFDR.js";
import "./chunk-QH6W3NVF.js";
import "./chunk-NOEAT6CX.js";
import "./chunk-4UWS5Y3N.js";
import "./chunk-DD4R5P6W.js";
import "./chunk-JNITUVXP.js";
import {
  arc_default,
  line_default
} from "./chunk-KSGA62R2.js";
import "./chunk-LOZEKOES.js";
import "./chunk-TOU7EVFQ.js";
import "./chunk-OAWQ6LOO.js";
import "./chunk-TLT4YIG3.js";
import "./chunk-KYBIQBXE.js";
import "./chunk-I6Y4O3RR.js";
import "./chunk-OMR2DT66.js";
import "./chunk-DQC5FFGV.js";
import "./chunk-HFNDKYVF.js";

// plots/profile/radarFacility2.ts
var ProfileRadarFacility2 = class extends profilePlot {
  static {
    this.type = "profileRadarFacility2";
  }
  constructor(opts) {
    super(opts, "profileRadarFacility2");
    this.radius = 200;
    this.isRadarFacility = true;
    this.lineGenerator = line_default().defined((d) => d !== null);
    this.arcGenerator = arc_default().innerRadius(0);
  }
  async init(appState) {
    await super.init(appState);
    const config = structuredClone(appState.plots.find((p) => p.id === this.id));
    for (const row of config.terms) {
      this.scoreTerms.push(row);
    }
    this.angle = Math.PI * 2 / config.terms.length;
  }
  async main() {
    await super.main();
    await this.setControls();
    this.plot();
  }
  /**
   * Called by the base class after super.setControls() builds the filter UI
   * and sets this.filter. One round-trip to termdb/profileRadarFacility2Scores
   * populates both this.data (aggregate) and this.sampleData (single-site).
   */
  async fetchRadarFacility2Scores() {
    const response = await dofetch3("termdb/profileRadarFacility2Scores", {
      body: {
        genome: this.state.vocab.genome,
        dslabel: this.state.vocab.dslabel,
        scoreTerms: this.scoreTerms.map((t) => ({
          score: { term: { id: t.score.term.id }, q: t.score.q },
          maxScore: typeof t.maxScore === "number" ? t.maxScore : { term: { id: t.maxScore.term.id }, q: t.maxScore.q }
        })),
        filter: this.filter,
        filterByUserSites: this.settings?.filterByUserSites,
        facilitySite: this.settings?.facilitySite || null
      }
    });
    if (response && "error" in response) throw response.error;
    this.sampleData = response.sampleData;
    return response;
  }
  plot() {
    const hasFacilityData = !!this.sampleData?.site;
    const { radarG, rows, data, data2 } = this.createSvgAndGrid(hasFacilityData);
    this.drawLines(radarG, data, data2, hasFacilityData);
    this.drawPercentLabels(radarG);
    this.drawTableAndLegend(rows, hasFacilityData);
  }
  createSvgAndGrid(hasFacilityData) {
    const width = this.isComparison ? 1e3 : 1100;
    const height = 630;
    this.dom.svg = this.dom.plotDiv.append("div").style("display", "inline-block").append("svg").attr("width", width).attr("height", height);
    const rightDiv = this.dom.plotDiv.append("div").style("display", "inline-block").style("vertical-align", "top").style("margin-top", "80px").style("margin-right", "20px");
    this.dom.tableDiv = rightDiv.append("div").attr("data-testid", "sjpp-profileRadarFacility2-data-table");
    this.dom.svg.append("text").attr("transform", `translate(90, 30)`).attr("font-weight", "bold").text(this.config.title);
    const x = 300;
    const y = 330;
    const radarG = this.dom.svg.append("g").attr("transform", `translate(${x},${y})`);
    this.radarG = radarG;
    this.legendG = this.dom.svg.append("g").attr("data-testid", "sjpp-profileRadarFacility2-legend").attr("font-size", "0.9em").attr("transform", `translate(${x + 320},${y - 150})`);
    this.filterG = this.dom.svg.append("g").attr("transform", `translate(${x + 320},${y - 50})`);
    for (let i2 = 0; i2 <= 10; i2++) this.drawPolygon(i2 * 10);
    const rows = [];
    const data = [];
    const data2 = [];
    const angle = this.angle;
    let i = 0;
    for (const item of this.config.terms) {
      const iangle = i * angle - Math.PI / 2;
      const rawFacility = this.getSamplePercentage(item);
      const rawGlobal = this.getPercentage(item);
      const p1 = hasFacilityData && Number.isFinite(rawFacility) ? rawFacility : null;
      const p2 = Number.isFinite(rawGlobal) ? rawGlobal : null;
      const tooltipDatum = { module: item.module, percentage1: p1, percentage2: p2 };
      this.radarG.append("path").datum(tooltipDatum).attr("fill", "transparent").attr(
        "d",
        this.arcGenerator({
          outerRadius: this.radius,
          startAngle: i * angle - angle / 2,
          endAngle: (i + 1) * angle - angle / 2
        })
      ).on("click", (event) => this.onMouseOver(event));
      if (p2 !== null) this.addDataPoint(iangle, data2, p2, false, tooltipDatum);
      else data2.push(null);
      if (p1 !== null) this.addDataPoint(iangle, data, p1, true, tooltipDatum);
      else data.push(null);
      const color = item.score.term.color;
      const bothPresent = p1 !== null && p2 !== null;
      const diff = bothPresent ? Math.abs(p1 - p2) : null;
      const diffRow = diff !== null ? { value: diff } : { value: "\u2014" };
      if (diff !== null && diff >= 20) diffRow.color = p2 > p1 ? "red" : "blue";
      rows.push([
        { color, disabled: true },
        { value: item.module },
        { value: p1 !== null ? p1 : "\u2014" },
        { value: p2 !== null ? p2 : "\u2014" },
        diffRow
      ]);
      this.drawModuleLabel(item.module, iangle);
      i++;
    }
    return { radarG, rows, data, data2 };
  }
  drawLines(radarG, data, data2, hasFacilityData) {
    const closePolygon = (arr) => {
      const firstDefined = arr.find((v) => v !== null);
      if (firstDefined) arr.push(firstDefined);
    };
    closePolygon(data2);
    const color1 = "blue";
    const color2 = "gray";
    if (hasFacilityData) {
      closePolygon(data);
      radarG.append("g").append("path").style("stroke", color1).attr("fill", "none").attr("stroke-width", "2px").attr("d", this.lineGenerator(data));
    }
    if (this.state.logged) {
      radarG.append("g").append("path").style("stroke", color2).attr("fill", "none").style("stroke-dasharray", "5, 5").attr("d", this.lineGenerator(data2));
    }
  }
  drawPercentLabels(radarG) {
    for (let i = 0; i <= 10; i++) {
      const percent = i * 10;
      radarG.append("text").attr("transform", `translate(0, ${-percent / 100 * this.radius - 2})`).attr("text-anchor", "end").style("font-size", "0.8rem").text(`${percent}%`).attr("pointer-events", "none");
    }
  }
  drawTableAndLegend(rows, hasFacilityData) {
    const columns = [
      { label: "Color" },
      { label: "Module" },
      { label: "Facility" },
      { label: "Global" },
      { label: "Difference*" }
    ];
    if (!this.isComparison) {
      renderTable({
        rows,
        columns,
        div: this.dom.tableDiv,
        showLines: true,
        resize: true
      });
      this.addDifferenceNote(
        `* Difference between site and aggregated scores. If bigger than 20 and positive shown in blue, if negative shown in red.`
      );
    }
    this.addFilterLegend();
    this.legendG.append("text").attr("text-anchor", "left").style("font-weight", "bold").text("Legend");
    if (hasFacilityData) {
      const site = this.sampleData.site;
      this.addFacilityLegendItem(`${site.label} / ${site.value}`, "blue", 0, "none");
      this.addFacilityLegendItem(this.config.score, "gray", 1, "5, 5");
    } else {
      this.legendG.append("text").attr("text-anchor", "start").style("font-style", "italic").style("font-size", "0.85em").attr("transform", "translate(0, 25)").text("No institutional data available for the current filter.");
      if (this.state.logged) {
        this.addFacilityLegendItem(this.config.score, "gray", 2, "5, 5");
      }
    }
  }
  addDifferenceNote(text) {
    const noteDiv = this.dom.tableDiv.append("div").attr("data-testid", "sjpp-profileRadarFacility2-difference-note").style("display", "flex").style("align-items", "center").style("gap", "6px").style("margin-top", "8px").style("font-size", "0.85em").style("font-style", "italic").style("color", "#555");
    noteDiv.append("span").attr("aria-hidden", "true").style("font-style", "normal").style("font-size", "1.1em").text("\u24D8");
    noteDiv.append("span").text(text);
  }
  drawModuleLabel(module, iangle) {
    const radius = this.radius;
    const leftSide = iangle > Math.PI / 2 && iangle <= 3 / 2 * Math.PI;
    const dx = radius * 1.1 * Math.cos(iangle);
    let dy = radius * 1.1 * Math.sin(iangle) - 10;
    const textElem = this.radarG.append("text").attr("x", `${dx}px`).attr("y", `${dy}px`).attr("font-size", "0.9em");
    const texts = module.split(" ");
    let span;
    for (const text of texts) {
      if (text != "and") {
        dy += 15;
        span = textElem.append("tspan").attr("x", `${dx}px`).attr("y", `${dy}px`).text(text);
      } else span.append("tspan").text(" and");
    }
    if (leftSide) textElem.attr("text-anchor", "end");
  }
  addDataPoint(iangle, data, percentage, isFacility, tooltipDatum) {
    const iradius = percentage / 100 * this.radius;
    const x = iradius * Math.cos(iangle);
    const y = iradius * Math.sin(iangle);
    const color = isFacility ? "blue" : "#aaa";
    this.radarG.append("g").attr("transform", `translate(${x}, ${y})`).append("circle").attr("r", 4).attr("fill", color).datum(tooltipDatum).on("click", (event) => this.onMouseOver(event));
    data.push([x, y]);
  }
  drawPolygon(percent) {
    const data = [];
    for (let i = 0; i < this.config.terms.length; i++) {
      const iangle = i * this.angle - Math.PI / 2;
      const iradius = percent / 100 * this.radius;
      const x = iradius * Math.cos(iangle);
      const y = iradius * Math.sin(iangle);
      data.push([x, y]);
    }
    data.push(data[0]);
    this.radarG.append("g").append("path").style("stroke", "#aaa").attr("fill", "none").attr("d", this.lineGenerator(data)).style("opacity", "0.5");
  }
  addFacilityLegendItem(text, color, index, strokeDash) {
    const step = 25;
    const y = step + index * step;
    const x = 35;
    this.legendG.append("path").attr("stroke", color).style("stroke-dasharray", strokeDash).attr("stroke-width", "2px").attr(
      "d",
      this.lineGenerator([
        [0, y - 5],
        [x, y - 5]
      ])
    );
    this.legendG.append("g").attr("transform", `translate(0, ${y - 5})`).append("circle").attr("r", 4).attr("fill", color);
    this.legendG.append("text").attr("font-size", "0.9em").attr("transform", `translate(${x + 5}, ${y})`).attr("text-anchor", "left").append("tspan").text(text);
  }
  onMouseOver(event) {
    const d = event.target.__data__;
    if (d?.module) {
      const label1 = "Facility";
      const label2 = this.config.score;
      const menu = this.tip.clear();
      menu.d.append("div").style("font-weight", "bold").text(d.module);
      const table = menu.d.append("table");
      let tr = table.append("tr");
      tr.append("td").text(label1);
      tr.append("td").text(d.percentage1 ?? "\u2014");
      tr = table.append("tr");
      tr.append("td").text(label2);
      tr.append("td").text(d.percentage2 ?? "\u2014");
      menu.show(event.clientX, event.clientY, true, true);
    } else this.onMouseOut(event);
  }
  /**
   * Returns the single-site percentage for term `d` — or `undefined` when the
   * server omitted the term (no eligible data) OR when `sampleData` is absent.
   * Callers must treat `undefined` as missing and NOT participate in arithmetic
   * or coordinate math — coercing to 0 would conflate missing with a real 0 score.
   */
  getSamplePercentage(d) {
    if (!d) return void 0;
    return this.sampleData?.term2Score?.[d.score.term.id];
  }
};
async function getPlotConfig(opts, app, _activeCohort) {
  try {
    const activeCohort = _activeCohort === void 0 ? app.getState().activeCohort : _activeCohort;
    const defaults = await getProfilePlotConfig(activeCohort, app, opts);
    if (!defaults) throw "default config not found in termdbConfig.plotConfigByCohort.profileRadarFacility2";
    const config = copyMerge(structuredClone(defaults), opts);
    const settings = getDefaultProfilePlotSettings();
    config.settings = {
      profileRadarFacility2: settings,
      controls: { isOpen: false }
    };
    const twlst = [];
    for (const row of config.terms) {
      row.score.q = row.maxScore.q = { mode: "continuous" };
      twlst.push(row.score);
      twlst.push(row.maxScore);
    }
    await fillTwLst(twlst, app.vocabApi);
    return config;
  } catch (e) {
    throw `${e} [profileRadarFacility2 getPlotConfig()]`;
  }
}
var profileRadarFacility2Init = getCompInit(ProfileRadarFacility2);
var componentInit = profileRadarFacility2Init;
export {
  componentInit,
  getPlotConfig,
  makeChartBtnMenu,
  profileRadarFacility2Init
};
//# sourceMappingURL=radarFacility2-DBPEV7VC.js.map
