import { unsafeCSS, LitElement, html } from "lit";
import { property, state, query } from "lit/decorators.js";
import componentStyle from "./polar-chart.css.js";
import chartCommonStyle from "../../charthelpers/chart-common.css.js";
import chartDebugStyle from "../../charthelpers/chart-debug.css.js";
import chartLegendStyle from "../../charthelpers/chart-legend.css.js";
import { customElement } from "../../decorator.js";
import { Priority } from "../../navigation-instruments/types.js";
import { Chart, PolarAreaController, RadialLinearScale, ArcElement, Tooltip } from "chart.js";
import { CHART_DIMENSIONS, CHART_SECTOR_ENHANCED_COLORS, CHART_SECTOR_DEFAULT_COLORS } from "../../charthelpers/constants.js";
import { getChartColorsOrDefault, getCssVariableValue } from "../../charthelpers/colors.js";
import { observeThemeChanges } from "../../charthelpers/theme.js";
import { createArcOuterLabelPlugin } from "../../charthelpers/outer-labels.js";
import { calculateFixedHeightChartLayout, formatNumericValue } from "../../charthelpers/canvas-layout.js";
import { getChartTooltipOptions } from "../../charthelpers/tooltip.js";
import { generateLegendHTML } from "../../charthelpers/legend.js";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __decorateClass = (decorators, target, key, kind) => {
  var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
  for (var i = decorators.length - 1, decorator; i >= 0; i--)
    if (decorator = decorators[i])
      result = (kind ? decorator(target, key, result) : decorator(result)) || result;
  if (kind && result) __defProp(target, key, result);
  return result;
};
Chart.register(PolarAreaController, RadialLinearScale, ArcElement, Tooltip);
const POLAR_BAR_DIMENSIONS = {
  ...CHART_DIMENSIONS,
  GAP_AND_BORDER_COLOR: "--instrument-frame-tertiary-color"
};
const POLAR_RECREATE_PROP_NAMES = [
  "showOuterLabels",
  "outerLabelUnit",
  "outerLabelMaxLength",
  "outerLabelDecimalPlaces",
  "showSectorLabels",
  "discreteColorStops",
  "showDebugOverlay",
  "fixedHeight",
  "showUnit"
];
const POLAR_WATCHED_PROP_NAMES = [
  "legend",
  "data",
  "colors",
  "priority",
  "monochrome",
  "discreteColorStops",
  "showSectorLabels",
  "showOuterLabels",
  "outerLabelUnit",
  "outerLabelMaxLength",
  "outerLabelDecimalPlaces",
  "showDebugOverlay",
  "fixedHeight",
  "showUnit"
];
let ObcPolarChart = class extends LitElement {
  constructor() {
    super(...arguments);
    this.data = [];
    this.colors = [];
    this.centerFirstSector = false;
    this.priority = Priority.regular;
    this.monochrome = false;
    this.discreteColorStops = false;
    this.showSectorLabels = false;
    this.showUnit = false;
    this.showOuterLabels = false;
    this.outerLabelUnit = "°";
    this.outerLabelMaxLength = 0;
    this.outerLabelDecimalPlaces = 0;
    this.fixedHeight = 320;
    this.legend = false;
    this.showDebugOverlay = false;
    this.formattedLabels = [];
    this.calculatedChartDiameter = CHART_DIMENSIONS.CHART_WIDTH;
    this.wasAboveThreshold = false;
  }
  hasAnyChanged(changed, props) {
    return props.some((prop) => changed.has(prop));
  }
  // Update external library AFTER render
  updated(changed) {
    super.updated(changed);
    if (this.hasAnyChanged(changed, POLAR_WATCHED_PROP_NAMES)) {
      const needsRecreation = this.hasAnyChanged(
        changed,
        POLAR_RECREATE_PROP_NAMES
      );
      if (needsRecreation) {
        this.chart?.destroy();
        this.createChart();
      } else {
        this.updateChart();
      }
    }
  }
  firstUpdated() {
    this.createChart();
    this.themeObserver = observeThemeChanges(() => this.updateChart());
    this.setupResizeObserver();
  }
  disconnectedCallback() {
    super.disconnectedCallback();
    this.chart?.destroy();
    this.themeObserver?.disconnect();
    this.resizeObserver?.disconnect();
  }
  /**
   * Setup resize observer to detect height threshold crossings
   * Recreates chart when crossing MIN_HEIGHT_WITH_LABELS (192px) to show/hide labels
   */
  setupResizeObserver() {
    if (!this.canvasEl) return;
    this.resizeObserver = new ResizeObserver(() => {
      const height2 = this.canvasEl?.clientHeight ?? 0;
      const isAboveThreshold = height2 >= CHART_DIMENSIONS.MIN_HEIGHT_WITH_LABELS;
      if (isAboveThreshold !== this.wasAboveThreshold) {
        this.wasAboveThreshold = isAboveThreshold;
        this.chart?.destroy();
        this.createChart();
      } else {
        this.updateChart();
      }
    });
    this.resizeObserver.observe(this.canvasEl);
    const height = this.canvasEl.clientHeight;
    this.wasAboveThreshold = height >= CHART_DIMENSIONS.MIN_HEIGHT_WITH_LABELS;
  }
  prepareChartData() {
    const values = this.data.map((d) => d.value);
    const labels = this.data.map((d) => d.label);
    const chartColors = getChartColorsOrDefault(
      this,
      this.colors,
      this.priority === Priority.enhanced ? CHART_SECTOR_ENHANCED_COLORS : CHART_SECTOR_DEFAULT_COLORS
    );
    const segmentColors = this.discreteColorStops ? values.map(() => "transparent") : values.map(
      (_, index) => this.monochrome ? chartColors[0] : chartColors[index % chartColors.length]
    );
    const numSectors = this.data.length;
    const displayLabels = this.showSectorLabels ? labels : Array.from({ length: numSectors }, (_, i) => {
      const angle = i * 360 / numSectors;
      return `${angle}`;
    });
    return {
      values,
      labels,
      colors: segmentColors,
      chartColors,
      // Pass resolved colors for use in plugin
      displayLabels
    };
  }
  getLayoutConfig() {
    return {
      unit: this.outerLabelUnit,
      showUnit: this.showUnit,
      outerLabelMaxLength: this.outerLabelMaxLength,
      decimalPlaces: this.outerLabelDecimalPlaces,
      data: this.showSectorLabels ? this.data : Array.from({ length: this.data.length }, (_, i) => ({
        label: "",
        value: i * 360 / this.data.length
      })),
      denominator: this.showSectorLabels ? 1 : 360
    };
  }
  getChartOptions() {
    const dimensions = calculateFixedHeightChartLayout({
      fixedHeight: this.fixedHeight,
      isHalfMode: false,
      showOuterLabels: this.showOuterLabels,
      canvasEl: this.canvasEl,
      layoutConfig: this.getLayoutConfig(),
      host: this
    });
    this.calculatedChartDiameter = dimensions.chartDiameter;
    this.formattedLabels = dimensions.formattedLabels;
    this.style.setProperty("--chart-width", `${dimensions.calculatedWidth}px`);
    this.style.setProperty("--chart-height", `${dimensions.actualHeight}px`);
    const dynamicPadding = dimensions.isTooSmall ? { top: 0, right: 0, bottom: 0, left: 0 } : {
      top: dimensions.topPadding,
      right: dimensions.rightPadding,
      bottom: dimensions.bottomPadding,
      left: dimensions.leftPadding
    };
    const chartColors = getChartColorsOrDefault(
      this,
      this.colors,
      CHART_SECTOR_DEFAULT_COLORS
    );
    const numTicks = this.discreteColorStops ? chartColors.length + 1 : 6;
    const maxValue = Math.max(...this.data.map((d) => d.value), 100);
    const numSectors = this.data.length;
    const anglePerSector = 360 / numSectors;
    const startAngle = this.centerFirstSector ? 0 : -anglePerSector / 2;
    return {
      responsive: true,
      maintainAspectRatio: true,
      aspectRatio: dimensions.aspectRatio,
      layout: {
        padding: dynamicPadding ?? POLAR_BAR_DIMENSIONS.CANVAS_PADDING
      },
      scales: {
        r: {
          startAngle,
          angleLines: {
            display: true,
            color: getCssVariableValue(
              this,
              POLAR_BAR_DIMENSIONS.GAP_AND_BORDER_COLOR
            ),
            lineWidth: 1
          },
          grid: {
            display: true,
            color: getCssVariableValue(
              this,
              POLAR_BAR_DIMENSIONS.GAP_AND_BORDER_COLOR
            ),
            lineWidth: 1
          },
          pointLabels: {
            // Always disable Chart.js built-in labels - we use our own outer label plugin
            display: false
          },
          ticks: {
            display: false,
            stepSize: maxValue / (numTicks - 1),
            count: numTicks
          },
          max: maxValue
        }
      },
      plugins: {
        legend: {
          display: false,
          labels: {
            generateLabels: () => []
            // Prevent Chart.js from generating labels internally
          },
          onClick: () => {
          }
          // Disable legend click handler
        },
        tooltip: {
          ...getChartTooltipOptions(this),
          enabled: !dimensions.isTooSmall,
          callbacks: {
            title: () => "",
            // No title line
            label: (context) => {
              const dataIndex = context.dataIndex;
              const data = this.data?.[dataIndex];
              const label = data?.label ?? "";
              const value = typeof data?.value === "number" ? data.value : Number(data?.value);
              return `${label} ${value}`;
            }
          }
        }
      },
      animation: false
    };
  }
  createDiscreteColorPlugin() {
    return {
      id: "discreteColors",
      beforeDatasetsDraw: (chart) => {
        if (!this.discreteColorStops) return;
        const { ctx, scales } = chart;
        const scale = scales.r;
        if (!scale) return;
        const centerX = scale.xCenter;
        const centerY = scale.yCenter;
        const maxRadius = this.calculatedChartDiameter / 2;
        const numSectors = this.data.length;
        const anglePerSector = Math.PI * 2 / numSectors;
        const rotationOffset = this.centerFirstSector ? 0 : -anglePerSector / 2;
        const chartColors = getChartColorsOrDefault(
          this,
          this.colors,
          this.priority === Priority.enhanced ? CHART_SECTOR_ENHANCED_COLORS : CHART_SECTOR_DEFAULT_COLORS
        );
        const numBands = chartColors.length;
        const maxValue = Math.max(...this.data.map((d) => d.value), 100);
        const colorStops = chartColors.reverse().map((color, index) => ({
          threshold: (index + 1) / numBands * maxValue,
          color
        }));
        ctx.save();
        this.data.forEach((dataPoint, sectorIndex) => {
          const sectorValue = dataPoint.value;
          const startAngle = sectorIndex * anglePerSector + rotationOffset - Math.PI / 2;
          const endAngle = startAngle + anglePerSector;
          let previousRadius = 0;
          colorStops.forEach((stop) => {
            const thresholdRadius = stop.threshold / maxValue * maxRadius;
            const sectorRadiusLimit = sectorValue / maxValue * maxRadius;
            let drawRadius;
            if (sectorRadiusLimit <= thresholdRadius) {
              drawRadius = sectorRadiusLimit;
            } else {
              drawRadius = thresholdRadius;
            }
            if (drawRadius > previousRadius) {
              ctx.fillStyle = stop.color;
              ctx.beginPath();
              ctx.arc(centerX, centerY, drawRadius, startAngle, endAngle);
              if (previousRadius > 0) {
                ctx.arc(
                  centerX,
                  centerY,
                  previousRadius,
                  endAngle,
                  startAngle,
                  true
                );
              } else {
                ctx.lineTo(centerX, centerY);
              }
              ctx.closePath();
              ctx.fill();
            }
            previousRadius = drawRadius;
            if (sectorRadiusLimit <= thresholdRadius) {
              return;
            }
          });
        });
        ctx.restore();
      }
    };
  }
  createChart() {
    if (!this.canvasEl || !this.canvasEl.isConnected) return;
    const ctx = this.canvasEl.getContext("2d");
    if (!ctx) return;
    const { values, colors, displayLabels } = this.prepareChartData();
    const plugins = [];
    if (this.discreteColorStops) {
      plugins.push(this.createDiscreteColorPlugin());
    }
    const chartOptions = this.getChartOptions();
    if (this.showOuterLabels && this.formattedLabels.length > 0) {
      const numSectors = values.length;
      const anglePerSector = Math.PI * 2 / (numSectors || 1);
      const rotationOffset = this.centerFirstSector ? 0 : -anglePerSector / 2;
      plugins.push(
        createArcOuterLabelPlugin(this, {
          formattedLabels: this.formattedLabels.slice(0, numSectors),
          rotationOffset,
          chartDiameter: this.calculatedChartDiameter,
          type: "polar"
        })
      );
    }
    this.chart = new Chart(ctx, {
      type: "polarArea",
      data: {
        labels: displayLabels,
        // Use angle labels or sector labels based on showSectorLabels
        datasets: [
          {
            data: values,
            backgroundColor: colors,
            borderWidth: 1,
            borderColor: getCssVariableValue(
              this,
              POLAR_BAR_DIMENSIONS.GAP_AND_BORDER_COLOR
            )
          }
        ]
      },
      options: chartOptions,
      plugins
    });
    requestAnimationFrame(() => this.updateLegend());
  }
  updateChart() {
    if (!this.chart || !this.canvasEl || !this.canvasEl.isConnected) return;
    const { values, colors, displayLabels } = this.prepareChartData();
    this.chart.data.labels = displayLabels;
    if (this.chart.data.datasets[0]) {
      this.chart.data.datasets[0].data = values;
      this.chart.data.datasets[0].backgroundColor = colors;
    }
    const latestOptions = this.getChartOptions();
    if (this.chart.options) {
      Object.assign(this.chart.options, latestOptions);
    }
    this.chart.update();
    requestAnimationFrame(() => this.updateLegend());
  }
  /**
   * Update the legend HTML content
   */
  updateLegend() {
    if (!this.legend || !this.legendDiv || !this.chart) return;
    const meta = this.chart.getDatasetMeta(0);
    if (!meta || !meta.controller) {
      return;
    }
    if (!this.data || this.data.length === 0) {
      this.legendDiv.innerHTML = "";
      return;
    }
    const denominator = this.showSectorLabels ? 1 : 360;
    const isPercentage = this.outerLabelUnit === "%";
    try {
      const legendItems = this.data.map((item, i) => {
        const style = meta.controller.getStyle(i, false);
        let label;
        let valueToFormat;
        if (this.showSectorLabels) {
          label = item.label;
          valueToFormat = item.value;
        } else {
          const angle = i * 360 / this.data.length;
          label = `${angle}${this.outerLabelUnit}`;
          valueToFormat = item.value;
        }
        const numericValue = formatNumericValue(
          valueToFormat,
          denominator,
          isPercentage,
          this.outerLabelDecimalPlaces
        );
        const showUnit = this.showUnit && this.outerLabelUnit;
        const value = `${numericValue}`;
        const unit = showUnit && this.showSectorLabels ? `${this.outerLabelUnit}` : "";
        return {
          fillStyle: style.backgroundColor,
          label,
          value,
          unit
        };
      });
      const legendHTML = generateLegendHTML(legendItems);
      this.legendDiv.innerHTML = legendHTML;
    } catch (error) {
      console.debug(
        "[obc-polar-chart] updateLegend: error generating legend HTML",
        error
      );
    }
  }
  render() {
    return html`
      <div class="wrapper">
        <canvas></canvas>
        ${this.legend ? html`<div class="legend"></div>` : ""}
      </div>
    `;
  }
};
ObcPolarChart.styles = [
  unsafeCSS(componentStyle),
  unsafeCSS(chartCommonStyle),
  unsafeCSS(chartLegendStyle),
  unsafeCSS(chartDebugStyle)
];
__decorateClass([
  property({ attribute: false })
], ObcPolarChart.prototype, "data", 2);
__decorateClass([
  property({ attribute: false })
], ObcPolarChart.prototype, "colors", 2);
__decorateClass([
  property({ type: String })
], ObcPolarChart.prototype, "priority", 2);
__decorateClass([
  property({ type: Boolean })
], ObcPolarChart.prototype, "monochrome", 2);
__decorateClass([
  property({ type: Boolean })
], ObcPolarChart.prototype, "discreteColorStops", 2);
__decorateClass([
  property({ type: Boolean })
], ObcPolarChart.prototype, "showSectorLabels", 2);
__decorateClass([
  property({ type: Boolean })
], ObcPolarChart.prototype, "showUnit", 2);
__decorateClass([
  property({ type: Boolean })
], ObcPolarChart.prototype, "showOuterLabels", 2);
__decorateClass([
  property({ type: String })
], ObcPolarChart.prototype, "outerLabelUnit", 2);
__decorateClass([
  property({ type: Number })
], ObcPolarChart.prototype, "outerLabelMaxLength", 2);
__decorateClass([
  property({ type: Number })
], ObcPolarChart.prototype, "outerLabelDecimalPlaces", 2);
__decorateClass([
  property({ type: Number, reflect: true })
], ObcPolarChart.prototype, "fixedHeight", 2);
__decorateClass([
  property({ type: Boolean, reflect: true })
], ObcPolarChart.prototype, "legend", 2);
__decorateClass([
  property({ type: Boolean, reflect: true })
], ObcPolarChart.prototype, "showDebugOverlay", 2);
__decorateClass([
  state()
], ObcPolarChart.prototype, "formattedLabels", 2);
__decorateClass([
  query("canvas")
], ObcPolarChart.prototype, "canvasEl", 2);
__decorateClass([
  query(".legend")
], ObcPolarChart.prototype, "legendDiv", 2);
ObcPolarChart = __decorateClass([
  customElement("obc-polar-chart")
], ObcPolarChart);
export {
  ObcPolarChart
};
//# sourceMappingURL=polar-chart.js.map
