import { unsafeCSS, LitElement, html } from "lit";
import { property, query } from "lit/decorators.js";
import { classMap } from "lit/directives/class-map.js";
import componentStyle from "./radial-bar-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, DoughnutController, 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 { calculateFixedHeightChartLayout } 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(DoughnutController, ArcElement, Tooltip);
const RADIAL_BAR_DIMENSIONS = {
  ...CHART_DIMENSIONS,
  CHART_WIDTH: 258,
  // Override: 256 + 2px to compensate for outer border visual appearance
  CANVAS_PADDING: 30,
  // Recude by the above 2px to keep chart area consistent
  GAP_AND_BORDER_COLOR: "--container-background-color",
  REMAINING_COLOR: "--border-outline-color",
  BORDER_RADIUS: 4,
  SPACING: 4,
  // Minimum visible arc thickness in pixels (excluding borders)
  MIN_CUTOUT_PERCENT: 20,
  // Minimum cutout percentage to maintain empty center
  DEFAULT_MAX_CUTOUT_PERCENT: 60
  // Default/maximum cutout percentage when space allows
};
const RADIAL_BAR_RECREATE_PROP_NAMES = [
  "circumference",
  "showDebugOverlay",
  "fixedHeight",
  "minRingThickness"
];
const RADIAL_BAR_WATCHED_PROP_NAMES = [
  "legend",
  "data",
  "colors",
  "priority",
  "max",
  "circumference",
  "showDebugOverlay",
  "fixedHeight",
  "minRingThickness"
];
let ObcRadialBarChart = class extends LitElement {
  constructor() {
    super(...arguments);
    this.data = [];
    this.colors = [];
    this.priority = Priority.regular;
    this.max = 100;
    this.circumference = 270;
    this.legend = false;
    this.showDebugOverlay = false;
    this.fixedHeight = 320;
    this.minRingThickness = 16;
    this.wasAboveThreshold = false;
  }
  hasAnyChanged(changed, props) {
    return props.some((prop) => changed.has(prop));
  }
  /**
   * Calculate optimal cutout percentage and whether rings should use minimum thickness
   * based on available chart space and number of rings.
   *
   * Algorithm:
   * 1. Calculate total space needed for all rings at minRingThickness
   * 2. If enough space: use equal thickness and adjust cutout
   * 3. If not enough space with minCutout: reduce cutout to minimum
   * 4. If still not enough: rings must be thinner than minimum
   *
   * @param chartDiameter - Available chart diameter in pixels
   * @param isTooSmall - Whether chart is below MIN_HEIGHT_WITH_LABELS (affects border width)
   * @returns Object with calculated cutout percentage and flag for using minimum thickness
   */
  calculateOptimalLayout(chartDiameter, isTooSmall) {
    const numRings = this.data.length;
    if (numRings === 0) {
      return {
        cutout: RADIAL_BAR_DIMENSIONS.DEFAULT_MAX_CUTOUT_PERCENT,
        useMinThickness: false
      };
    }
    const effectiveSpacing = isTooSmall ? RADIAL_BAR_DIMENSIONS.SPACING / 2 : RADIAL_BAR_DIMENSIONS.SPACING;
    const totalSpacePerRing = this.minRingThickness + effectiveSpacing;
    const radius = chartDiameter / 2;
    const totalRingsSpace = numRings * totalSpacePerRing;
    const remainingSpace = radius - totalRingsSpace;
    const calculatedCutoutPercent = remainingSpace / radius * 100;
    if (calculatedCutoutPercent >= RADIAL_BAR_DIMENSIONS.MIN_CUTOUT_PERCENT) {
      return {
        cutout: Math.min(
          calculatedCutoutPercent,
          RADIAL_BAR_DIMENSIONS.DEFAULT_MAX_CUTOUT_PERCENT
        ),
        useMinThickness: true
      };
    } else {
      const minCutoutSpace = radius * RADIAL_BAR_DIMENSIONS.MIN_CUTOUT_PERCENT / 100;
      const availableRingSpace = radius - minCutoutSpace;
      const spacePerRingWithMinCutout = availableRingSpace / numRings;
      if (spacePerRingWithMinCutout >= totalSpacePerRing) {
        return {
          cutout: RADIAL_BAR_DIMENSIONS.MIN_CUTOUT_PERCENT,
          useMinThickness: true
        };
      } else {
        return {
          cutout: RADIAL_BAR_DIMENSIONS.MIN_CUTOUT_PERCENT,
          useMinThickness: false
        };
      }
    }
  }
  // Update external library AFTER render
  updated(changed) {
    super.updated(changed);
    if (this.hasAnyChanged(changed, RADIAL_BAR_WATCHED_PROP_NAMES)) {
      const needsRecreation = this.hasAnyChanged(
        changed,
        RADIAL_BAR_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 >= RADIAL_BAR_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 >= RADIAL_BAR_DIMENSIONS.MIN_HEIGHT_WITH_LABELS;
  }
  prepareChartData() {
    const chartColors = getChartColorsOrDefault(
      this,
      this.colors,
      this.priority === Priority.enhanced ? CHART_SECTOR_ENHANCED_COLORS : CHART_SECTOR_DEFAULT_COLORS
    );
    const remainingColor = getCssVariableValue(
      this,
      RADIAL_BAR_DIMENSIONS.REMAINING_COLOR
    );
    const borderColor = getCssVariableValue(
      this,
      RADIAL_BAR_DIMENSIONS.GAP_AND_BORDER_COLOR
    );
    const height = this.canvasEl?.clientHeight ?? 0;
    const isTooSmall = height < RADIAL_BAR_DIMENSIONS.MIN_HEIGHT_WITH_LABELS;
    const effectiveSpacing = isTooSmall ? RADIAL_BAR_DIMENSIONS.SPACING / 2 : RADIAL_BAR_DIMENSIONS.SPACING;
    const datasets = this.data.map((value, index) => {
      const remaining = Math.max(0, this.max - value);
      const color = chartColors[index % chartColors.length] ?? CHART_SECTOR_DEFAULT_COLORS[0];
      return {
        data: [value, remaining],
        backgroundColor: [color, remainingColor],
        borderWidth: effectiveSpacing,
        // Use reduced spacing for small charts (1px + 1px borders)
        borderColor,
        // Use container section color for gaps
        borderRadius: RADIAL_BAR_DIMENSIONS.BORDER_RADIUS,
        spacing: 0,
        // Spacing between colored and remaining segments
        weight: 1
        // Equal weight for all rings
      };
    });
    return { datasets };
  }
  getChartOptions() {
    const rotation = 0;
    const dimensions = calculateFixedHeightChartLayout({
      fixedHeight: this.fixedHeight,
      isHalfMode: false,
      // Always full circle dimensions, circumference only controls what's shown
      showOuterLabels: false,
      // Radial bar charts don't have outer labels
      canvasEl: this.canvasEl,
      layoutConfig: {
        data: [],
        // No data labels for radial bars
        denominator: 100
      },
      host: this
    });
    this.style.setProperty("--chart-width", `${dimensions.calculatedWidth}px`);
    this.style.setProperty("--chart-height", `${dimensions.actualHeight}px`);
    const dynamicPadding = dimensions.isTooSmall ? 0 : RADIAL_BAR_DIMENSIONS.CANVAS_PADDING;
    const chartDiameter = dimensions.isTooSmall ? dimensions.actualHeight - dynamicPadding * 2 : RADIAL_BAR_DIMENSIONS.CHART_WIDTH;
    const { cutout: optimalCutout } = this.calculateOptimalLayout(
      chartDiameter,
      dimensions.isTooSmall
    );
    return {
      responsive: true,
      maintainAspectRatio: true,
      aspectRatio: dimensions.aspectRatio,
      rotation,
      circumference: this.circumference,
      cutout: `${optimalCutout}%`,
      layout: {
        padding: {
          top: dynamicPadding,
          right: dynamicPadding,
          bottom: dynamicPadding,
          left: dynamicPadding
        }
      },
      plugins: {
        legend: {
          display: false,
          labels: {
            generateLabels: () => []
            // Prevent Chart.js from generating labels internally
          },
          onClick: () => {
          }
          // Disable legend click handler
        },
        tooltip: {
          ...getChartTooltipOptions(this),
          enabled: !dimensions.isTooSmall,
          filter: (tooltipItem) => tooltipItem.label !== "Remaining",
          callbacks: {
            title: () => "",
            label: (context) => {
              const datasetIndex = context.datasetIndex;
              const valueIndex = context.dataIndex;
              if (valueIndex !== 0) return "";
              const ringLabel = `Ring ${datasetIndex + 1}`;
              const value = context.parsed;
              return `${ringLabel} ${value}`;
            }
          }
        }
      },
      animation: {
        animateRotate: false,
        animateScale: false
      }
    };
  }
  createChart() {
    if (!this.canvasEl || !this.canvasEl.isConnected) return;
    const ctx = this.canvasEl.getContext("2d");
    if (!ctx) return;
    const { datasets } = this.prepareChartData();
    this.chart = new Chart(ctx, {
      type: "doughnut",
      data: {
        labels: this.data.map((_, i) => `Ring ${i + 1}`),
        datasets
      },
      options: this.getChartOptions()
    });
    requestAnimationFrame(() => this.updateLegend());
  }
  updateChart() {
    if (!this.chart || !this.canvasEl || !this.canvasEl.isConnected) return;
    const { datasets } = this.prepareChartData();
    this.chart.data.labels = this.data.map((_, i) => `Ring ${i + 1}`);
    this.chart.data.datasets = datasets;
    const newOptions = this.getChartOptions();
    if (this.chart.options) {
      Object.assign(this.chart.options, newOptions);
    }
    this.chart.update();
    requestAnimationFrame(() => this.updateLegend());
  }
  /**
   * Update the legend HTML content
   */
  updateLegend() {
    if (!this.legend || !this.legendDiv || !this.chart) return;
    if (!this.data || this.data.length === 0) {
      this.legendDiv.innerHTML = "";
      return;
    }
    try {
      const chartColors = getChartColorsOrDefault(
        this,
        this.colors,
        this.priority === Priority.enhanced ? CHART_SECTOR_ENHANCED_COLORS : CHART_SECTOR_DEFAULT_COLORS
      );
      const legendItems = this.data.map((value, i) => {
        const color = chartColors[i % chartColors.length] ?? (this.priority === Priority.enhanced ? CHART_SECTOR_ENHANCED_COLORS[0] : CHART_SECTOR_DEFAULT_COLORS[0]);
        return {
          fillStyle: color,
          label: `Ring ${i + 1}`,
          value: value.toString(),
          unit: ""
        };
      });
      const legendHTML = generateLegendHTML(legendItems);
      this.legendDiv.innerHTML = legendHTML;
    } catch (error) {
      console.debug(
        "[obc-radial-bar-chart] updateLegend: error generating legend HTML",
        error
      );
    }
  }
  render() {
    const wrapperClasses = {
      wrapper: true,
      debug: this.showDebugOverlay
    };
    return html`
      <div class=${classMap(wrapperClasses)}>
        <canvas></canvas>
        ${this.legend ? html`<div class="legend"></div>` : ""}
      </div>
    `;
  }
};
ObcRadialBarChart.styles = [
  unsafeCSS(componentStyle),
  unsafeCSS(chartCommonStyle),
  unsafeCSS(chartLegendStyle),
  unsafeCSS(chartDebugStyle)
];
__decorateClass([
  property({ attribute: false })
], ObcRadialBarChart.prototype, "data", 2);
__decorateClass([
  property({ attribute: false })
], ObcRadialBarChart.prototype, "colors", 2);
__decorateClass([
  property({ type: String })
], ObcRadialBarChart.prototype, "priority", 2);
__decorateClass([
  property({ type: Number })
], ObcRadialBarChart.prototype, "max", 2);
__decorateClass([
  property({ type: Number })
], ObcRadialBarChart.prototype, "circumference", 2);
__decorateClass([
  property({ type: Boolean, reflect: true })
], ObcRadialBarChart.prototype, "legend", 2);
__decorateClass([
  property({ type: Boolean, reflect: true })
], ObcRadialBarChart.prototype, "showDebugOverlay", 2);
__decorateClass([
  property({ type: Number, reflect: true })
], ObcRadialBarChart.prototype, "fixedHeight", 2);
__decorateClass([
  property({
    type: Number
  })
], ObcRadialBarChart.prototype, "minRingThickness", 2);
__decorateClass([
  query("canvas")
], ObcRadialBarChart.prototype, "canvasEl", 2);
__decorateClass([
  query(".legend")
], ObcRadialBarChart.prototype, "legendDiv", 2);
ObcRadialBarChart = __decorateClass([
  customElement("obc-radial-bar-chart")
], ObcRadialBarChart);
export {
  ObcRadialBarChart
};
//# sourceMappingURL=radial-bar-chart.js.map
