import { LitElement, html, unsafeCSS } from "lit";
import { property, query } from "lit/decorators.js";
import componentStyle from "./chart-line-base.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 { Chart, LineController, LineElement, PointElement, ArcElement, CategoryScale, LinearScale, TimeScale, Filler, Tooltip } from "chart.js";
import { InstrumentState, Priority, FrameStyle, BorderRadiusPosition } from "../../navigation-instruments/types.js";
import { CHART_DIMENSIONS, RECTANGULAR_CHART_DIMENSIONS, CHART_SECTOR_ENHANCED_COLORS, CHART_SECTOR_DEFAULT_COLORS, CHART_AREA_BACKGROUND_COLOR_VAR, LINE_GRAPH_GRID_CONFIG, LINE_GRAPH_LABEL_CONFIG } from "../../charthelpers/constants.js";
import { getCssVariableValue, applyAlphaToColor, getChartColorsOrDefault } from "../../charthelpers/colors.js";
import { observeThemeChanges } from "../../charthelpers/theme.js";
import { formatNumericValue } from "../../charthelpers/canvas-layout.js";
import { getChartTooltipOptions } from "../../charthelpers/tooltip.js";
import { generateLegendHTML } from "../../charthelpers/legend.js";
import { readExternalScaleBorderRadiusPx, ScaleType, startExternalScaleBorderRadiusObserver, EXTERNAL_SCALE_BORDER_RADIUS_CSS_VAR } from "../external-scale/external-scale.js";
var __defProp = Object.defineProperty;
var __decorateClass = (decorators, target, key, kind) => {
  var result = void 0;
  for (var i = decorators.length - 1, decorator; i >= 0; i--)
    if (decorator = decorators[i])
      result = decorator(target, key, result) || result;
  if (result) __defProp(target, key, result);
  return result;
};
Chart.register(
  LineController,
  LineElement,
  PointElement,
  ArcElement,
  CategoryScale,
  LinearScale,
  TimeScale,
  Filler,
  Tooltip
);
var XAxisType = /* @__PURE__ */ ((XAxisType2) => {
  XAxisType2["category"] = "category";
  XAxisType2["time"] = "time";
  return XAxisType2;
})(XAxisType || {});
var YAxisPosition = /* @__PURE__ */ ((YAxisPosition2) => {
  YAxisPosition2["left"] = "left";
  YAxisPosition2["right"] = "right";
  return YAxisPosition2;
})(YAxisPosition || {});
var LineMode = /* @__PURE__ */ ((LineMode2) => {
  LineMode2["smooth"] = "smooth";
  LineMode2["straight"] = "straight";
  LineMode2["stepped"] = "stepped";
  return LineMode2;
})(LineMode || {});
var TimeDisplay = /* @__PURE__ */ ((TimeDisplay2) => {
  TimeDisplay2["minutes"] = "minutes";
  TimeDisplay2["date"] = "date";
  return TimeDisplay2;
})(TimeDisplay || {});
const LINE_GRAPH_WATCHED_PROP_NAMES = [
  "data",
  "datasets",
  "labels",
  "colors",
  "xAxisType",
  "yAxisPosition",
  "yAxes",
  "showGrid",
  "showGridX",
  "showGridY",
  "showTickMarks",
  "showPoints",
  "lineMode",
  "unit",
  // Used in tooltip display
  "timeDisplay",
  "xTicksLimit",
  "xStepSize",
  "yTicksLimit",
  "yStepSize",
  "priority",
  // Triggers color palette change
  "borderRadiusPosition",
  // Triggers border styling update
  "borderRadiusPositionExternalScales",
  // Triggers external scale border styling update
  // legend only affects HTML; do not use it to drive chart updates
  "width",
  "height",
  "fixedAspectRatioScaling"
  // Triggers responsive mode change
];
const LINE_GRAPH_RECREATE_PROP_NAMES = [
  "showDebugOverlay",
  "width",
  "height",
  "fixedAspectRatioScaling"
];
const _ObcChartLineBase = class _ObcChartLineBase extends LitElement {
  constructor() {
    super(...arguments);
    this.data = [];
    this.datasets = void 0;
    this.labels = void 0;
    this.colors = [];
    this.legend = false;
    this.showDebugOverlay = false;
    this.width = 480;
    this.height = 320;
    this.fixedAspectRatioScaling = false;
    this.scaleReferenceSize = 384;
    this.xAxisType = "category";
    this.yAxisPosition = "left";
    this.yAxes = void 0;
    this.showGrid = false;
    this.showGridX = false;
    this.showGridY = false;
    this.showTickMarks = false;
    this.DEFAULT_TENSION = 0.4;
    this.POINT_RADIUS = 3;
    this.showPoints = false;
    this.lineMode = "smooth";
    this.unit = "";
    this.timeDisplay = "date";
    this.xTicksLimit = void 0;
    this.xStepSize = void 0;
    this.yTicksLimit = void 0;
    this.yStepSize = void 0;
    this.state = InstrumentState.active;
    this.priority = Priority.regular;
    this.frameStyle = FrameStyle.regular;
    this.borderRadiusPosition = void 0;
    this.borderRadiusPositionExternalScales = void 0;
    this.instrumentMode = false;
    this.borderRadius = void 0;
    this.wasAboveThreshold = false;
    this.externalScaleDimensions = /* @__PURE__ */ new Map();
    this.isUpdatingScales = false;
    this.currentBorderRadiusPx = 8;
    this.computedWidth = 480;
    this.computedHeight = 320;
    this.updateBorderRadius = () => {
      if (!this.canvasEl) return;
      let next;
      if (this.instrumentMode) {
        next = this.borderRadius ?? 8;
      } else {
        next = readExternalScaleBorderRadiusPx(
          this.canvasEl,
          ScaleType.regular,
          EXTERNAL_SCALE_BORDER_RADIUS_CSS_VAR
        );
      }
      if (this.currentBorderRadiusPx !== next) {
        this.currentBorderRadiusPx = next;
        if (this.chart) {
          this.chart.destroy();
          this.createChart();
        }
      }
    };
    this.handleSlotChange = () => {
      this.externalScaleDimensions.clear();
      this.waitForScaleDimensions();
    };
    this.handleScaleDimensionsChanged = (e) => {
      if (this.isUpdatingScales) return;
      const event = e;
      const { side, thickness } = event.detail;
      const previousThickness = this.externalScaleDimensions.get(side);
      if (previousThickness === thickness) return;
      this.externalScaleDimensions.set(side, thickness);
      if (this.dimensionUpdateTimer) {
        clearTimeout(this.dimensionUpdateTimer);
      }
      this.dimensionUpdateTimer = setTimeout(() => {
        this.syncScalesAndChart();
      }, 16);
    };
  }
  /**
   * Should fill be applied to this chart?
   * Line graph returns false, area graph returns true.
   * Must be implemented in subclass.
   */
  shouldApplyFill() {
    throw new Error("shouldApplyFill() must be implemented in subclass");
  }
  /**
   * Get fill mode for area rendering.
   * Line graph returns undefined, area graph returns 'semitransparent' | 'solid' | 'threshold'.
   * Must be implemented in subclass.
   */
  getFillMode() {
    throw new Error("getFillMode() must be implemented in subclass");
  }
  /**
   * Should multi-series datasets be stacked?
   * Line graph returns false, area graph returns stacked property value.
   * Must be implemented in subclass.
   */
  shouldStack() {
    throw new Error("shouldStack() must be implemented in subclass");
  }
  /**
   * Compute which corners should be rounded based on borderRadiusPosition and
   * which external scales are present.
   *
   * Logic:
   * - Opposite scales (left+right OR top+bottom) → no rounding (middleChild behavior)
   * - Perpendicular scales (e.g., right+bottom):
   *   - innerFirstChild → round corner adjacent to both scales
   *   - outerLastChild → round free corner opposite to scales
   * - Single-side scales:
   *   - When external scale is on RIGHT, chart is on LEFT
   *     - innerFirstChild → round LEFT corners (top-left + bottom-left)
   *     - outerLastChild → round RIGHT corners (top-right + bottom-right)
   *   - When external scale is on LEFT, chart is on RIGHT (opposite)
   *   - When external scale is on TOP, chart is on BOTTOM
   *     - innerFirstChild → round BOTTOM corners (bottom-left + bottom-right)
   *     - outerLastChild → round TOP corners (top-left + top-right)
   *   - When external scale is on BOTTOM, chart is on TOP (opposite)
   * - middleChild → no rounding
   */
  /**
   * Check if a slotted scale element is actually visible (renders content).
   * For bar-vertical/bar-horizontal elements, checks hasBar and hasScale properties.
   */
  hasVisibleScale(side) {
    const slotMap = {
      left: this.leftScaleSlot,
      right: this.rightScaleSlot,
      top: this.topScaleSlot,
      bottom: this.bottomScaleSlot
    };
    const slot = slotMap[side];
    const elements = slot?.assignedElements() ?? [];
    return elements.some((el) => {
      const barEl = el;
      if ("hasBar" in barEl && "hasScale" in barEl) {
        return barEl.hasBar === true || barEl.hasScale === true;
      }
      return true;
    });
  }
  computeRoundedCorners() {
    if (!this.borderRadiusPosition) {
      return {
        topLeft: false,
        topRight: false,
        bottomLeft: false,
        bottomRight: false
      };
    }
    if (this.borderRadiusPosition === BorderRadiusPosition.middleChild) {
      return {
        topLeft: false,
        topRight: false,
        bottomLeft: false,
        bottomRight: false
      };
    }
    if (this.borderRadiusPosition === BorderRadiusPosition.middleRoundedChild) {
      return {
        topLeft: true,
        topRight: true,
        bottomLeft: true,
        bottomRight: true
      };
    }
    const hasLeft = this.hasVisibleScale("left");
    const hasRight = this.hasVisibleScale("right");
    const hasTop = this.hasVisibleScale("top");
    const hasBottom = this.hasVisibleScale("bottom");
    if (hasLeft && hasRight || hasTop && hasBottom) {
      return {
        topLeft: false,
        topRight: false,
        bottomLeft: false,
        bottomRight: false
      };
    }
    const result = {
      topLeft: false,
      topRight: false,
      bottomLeft: false,
      bottomRight: false
    };
    const isInner = this.borderRadiusPosition === BorderRadiusPosition.innerFirstChild;
    const isOuter = this.borderRadiusPosition === BorderRadiusPosition.outerLastChild;
    if (hasRight && hasBottom) {
      if (isInner) {
        result.bottomRight = true;
      } else if (isOuter) {
        result.topLeft = true;
      }
    } else if (hasRight && hasTop) {
      if (isInner) {
        result.topRight = true;
      } else if (isOuter) {
        result.bottomLeft = true;
      }
    } else if (hasLeft && hasBottom) {
      if (isInner) {
        result.bottomLeft = true;
      } else if (isOuter) {
        result.topRight = true;
      }
    } else if (hasLeft && hasTop) {
      if (isInner) {
        result.topLeft = true;
      } else if (isOuter) {
        result.bottomRight = true;
      }
    } else if (hasRight && !hasLeft) {
      if (isInner) {
        result.topLeft = true;
        result.bottomLeft = true;
      } else if (isOuter) {
        result.topRight = true;
        result.bottomRight = true;
      }
    } else if (hasLeft && !hasRight) {
      if (isInner) {
        result.topRight = true;
        result.bottomRight = true;
      } else if (isOuter) {
        result.topLeft = true;
        result.bottomLeft = true;
      }
    } else if (hasBottom && !hasTop) {
      if (isInner) {
        result.topLeft = true;
        result.topRight = true;
      } else if (isOuter) {
        result.bottomLeft = true;
        result.bottomRight = true;
      }
    } else if (hasTop && !hasBottom) {
      if (isInner) {
        result.bottomLeft = true;
        result.bottomRight = true;
      } else if (isOuter) {
        result.topLeft = true;
        result.topRight = true;
      }
    }
    return result;
  }
  /**
   * Create a Chart.js plugin that draws a border around the chart area with selective corner rounding
   * and clips content to that border.
   */
  createBorderPlugin() {
    const corners = this.computeRoundedCorners();
    const radius = this.currentBorderRadiusPx;
    let didApplyClip = false;
    const buildRoundedRectPath = (ctx, rect, cornerRadius) => {
      const { x, y, width, height } = rect;
      if (width <= 0 || height <= 0) return;
      const r = Math.max(
        0,
        Math.min(cornerRadius, Math.min(width, height) / 2)
      );
      ctx.moveTo(x + (corners.topLeft ? r : 0), y);
      ctx.lineTo(x + width - (corners.topRight ? r : 0), y);
      if (corners.topRight) {
        ctx.arcTo(x + width, y, x + width, y + r, r);
      }
      ctx.lineTo(x + width, y + height - (corners.bottomRight ? r : 0));
      if (corners.bottomRight) {
        ctx.arcTo(x + width, y + height, x + width - r, y + height, r);
      }
      ctx.lineTo(x + (corners.bottomLeft ? r : 0), y + height);
      if (corners.bottomLeft) {
        ctx.arcTo(x, y + height, x, y + height - r, r);
      }
      ctx.lineTo(x, y + (corners.topLeft ? r : 0));
      if (corners.topLeft) {
        ctx.arcTo(x, y, x + r, y, r);
      }
    };
    return {
      id: "chartAreaBorder",
      beforeDatasetsDraw: (chart) => {
        const ctx = chart.ctx;
        const chartArea = chart.chartArea;
        if (!chartArea) return;
        const borderWidthPx = 1;
        const clipInset = borderWidthPx;
        const { top, right, bottom, left } = chartArea;
        const rect = {
          x: left + clipInset,
          y: top + clipInset,
          width: right - left - clipInset * 2,
          height: bottom - top - clipInset * 2
        };
        const clipRadius = Math.max(0, radius - clipInset);
        ctx.save();
        didApplyClip = true;
        ctx.beginPath();
        buildRoundedRectPath(ctx, rect, clipRadius);
        ctx.closePath();
        if (this.instrumentMode) {
          const backgroundColor = getCssVariableValue(
            this,
            CHART_AREA_BACKGROUND_COLOR_VAR
          );
          ctx.fillStyle = backgroundColor;
          ctx.fill();
        }
        ctx.clip();
      },
      afterDraw: (chart) => {
        const ctx = chart.ctx;
        const chartArea = chart.chartArea;
        if (!chartArea) return;
        const borderWidthPx = 1;
        const strokeInset = borderWidthPx / 2;
        const { top, right, bottom, left } = chartArea;
        const rect = {
          x: left + strokeInset,
          y: top + strokeInset,
          width: right - left - strokeInset * 2,
          height: bottom - top - strokeInset * 2
        };
        const strokeRadius = Math.max(0, radius - strokeInset);
        const skipTop = this.hasVisibleScale("top");
        const skipRight = this.hasVisibleScale("right");
        const skipBottom = this.hasVisibleScale("bottom");
        const skipLeft = this.hasVisibleScale("left");
        const borderColor = getCssVariableValue(
          this,
          "--instrument-frame-tertiary-color"
        );
        ctx.save();
        ctx.strokeStyle = borderColor;
        ctx.lineWidth = borderWidthPx;
        const { x, y, width, height } = rect;
        const r = Math.max(
          0,
          Math.min(strokeRadius, Math.min(width, height) / 2)
        );
        if (!skipTop && !skipRight && !skipBottom && !skipLeft) {
          ctx.beginPath();
          buildRoundedRectPath(
            ctx,
            rect,
            strokeRadius
          );
          ctx.closePath();
          ctx.stroke();
        } else {
          if (!skipTop) {
            ctx.beginPath();
            if (!skipLeft && corners.topLeft) {
              ctx.moveTo(x + r, y);
            } else {
              ctx.moveTo(x, y);
            }
            if (!skipRight && corners.topRight) {
              ctx.lineTo(x + width - r, y);
            } else {
              ctx.lineTo(x + width, y);
            }
            ctx.stroke();
          }
          if (!skipRight) {
            ctx.beginPath();
            if (!skipTop && corners.topRight) {
              ctx.moveTo(x + width, y + r);
            } else {
              ctx.moveTo(x + width, y);
            }
            if (!skipBottom && corners.bottomRight) {
              ctx.lineTo(x + width, y + height - r);
            } else {
              ctx.lineTo(x + width, y + height);
            }
            ctx.stroke();
          }
          if (!skipBottom) {
            ctx.beginPath();
            if (!skipRight && corners.bottomRight) {
              ctx.moveTo(x + width - r, y + height);
            } else {
              ctx.moveTo(x + width, y + height);
            }
            if (!skipLeft && corners.bottomLeft) {
              ctx.lineTo(x + r, y + height);
            } else {
              ctx.lineTo(x, y + height);
            }
            ctx.stroke();
          }
          if (!skipLeft) {
            ctx.beginPath();
            if (!skipBottom && corners.bottomLeft) {
              ctx.moveTo(x, y + height - r);
            } else {
              ctx.moveTo(x, y + height);
            }
            if (!skipTop && corners.topLeft) {
              ctx.lineTo(x, y + r);
            } else {
              ctx.lineTo(x, y);
            }
            ctx.stroke();
          }
          if (!skipTop && !skipLeft && corners.topLeft) {
            ctx.beginPath();
            ctx.arc(x + r, y + r, r, Math.PI, Math.PI * 1.5);
            ctx.stroke();
          }
          if (!skipTop && !skipRight && corners.topRight) {
            ctx.beginPath();
            ctx.arc(x + width - r, y + r, r, Math.PI * 1.5, Math.PI * 2);
            ctx.stroke();
          }
          if (!skipRight && !skipBottom && corners.bottomRight) {
            ctx.beginPath();
            ctx.arc(x + width - r, y + height - r, r, 0, Math.PI * 0.5);
            ctx.stroke();
          }
          if (!skipBottom && !skipLeft && corners.bottomLeft) {
            ctx.beginPath();
            ctx.arc(x + r, y + height - r, r, Math.PI * 0.5, Math.PI);
            ctx.stroke();
          }
        }
        ctx.restore();
        if (this.showPoints) {
          ctx.save();
          chart.data.datasets.forEach((_ds, datasetIndex) => {
            const meta = chart.getDatasetMeta(datasetIndex);
            if (!meta || meta.hidden) return;
            (meta.data ?? []).forEach((el) => {
              const point = el;
              if (point.skip) return;
              const r2 = point.options?.radius;
              if (typeof r2 === "number" && r2 <= 0) return;
              point.draw(ctx);
            });
          });
          ctx.restore();
        }
      },
      afterDatasetsDraw: (chart) => {
        if (didApplyClip) {
          chart.ctx.restore();
          didApplyClip = false;
        }
      }
    };
  }
  /**
   * Check if any external scales are slotted
   */
  hasExternalScales() {
    const top = this.topScaleSlot?.assignedElements() ?? [];
    const bottom = this.bottomScaleSlot?.assignedElements() ?? [];
    const left = this.leftScaleSlot?.assignedElements() ?? [];
    const right = this.rightScaleSlot?.assignedElements() ?? [];
    return top.length > 0 || bottom.length > 0 || left.length > 0 || right.length > 0;
  }
  /**
   * Wait for all slotted scales to report their dimensions
   */
  async waitForScaleDimensions() {
    if (!this.hasExternalScales()) {
      this.requestUpdate();
      return;
    }
    const scaleElements = [];
    [
      this.topScaleSlot,
      this.bottomScaleSlot,
      this.leftScaleSlot,
      this.rightScaleSlot
    ].forEach((slot) => {
      if (slot) {
        const assigned = slot.assignedElements();
        scaleElements.push(...assigned);
      }
    });
    const setScaleProps = (slot) => {
      if (!slot) return;
      const scales = slot.assignedElements();
      scales.forEach((scale) => {
        scale.fixedAspectRatio = this.fixedAspectRatioScaling;
        scale.scaleReferenceSize = this.scaleReferenceSize;
      });
    };
    setScaleProps(this.leftScaleSlot);
    setScaleProps(this.rightScaleSlot);
    setScaleProps(this.topScaleSlot);
    setScaleProps(this.bottomScaleSlot);
    await Promise.all(
      scaleElements.map(
        (el) => "updateComplete" in el && typeof el.updateComplete === "object" ? el.updateComplete : Promise.resolve()
      )
    );
    if (this.externalScaleDimensions.size === 0 && scaleElements.length > 0) {
      await new Promise((resolve) => setTimeout(resolve, 50));
    }
    this.syncScalesAndChart();
  }
  /**
   * Synchronize scale and chart dimensions/data
   * This is the main coordination function
   */
  syncScalesAndChart() {
    if (this.isUpdatingScales) return;
    this.isUpdatingScales = true;
    try {
      const padding = this.calculatePaddingFromScales();
      const effectiveWidth = this.width - padding.left - padding.right;
      const effectiveHeight = this.height - padding.top - padding.bottom;
      if (effectiveWidth <= 0 || effectiveHeight <= 0) {
        console.warn("[chart-line-base] Invalid effective dimensions", {
          width: this.width,
          height: this.height,
          padding,
          effectiveWidth,
          effectiveHeight
        });
        return;
      }
      this.updateScaleProperties(padding);
      if (this.chart) {
        this.chart.destroy();
      }
      this.createChart();
    } finally {
      this.isUpdatingScales = false;
    }
  }
  /**
   * Calculate chart padding from external scale dimensions
   */
  calculatePaddingFromScales() {
    const defaultPadding = CHART_DIMENSIONS.CANVAS_PADDING;
    const padding = {
      top: this.externalScaleDimensions.get("top") ?? defaultPadding,
      right: this.externalScaleDimensions.get("right") ?? defaultPadding,
      bottom: this.externalScaleDimensions.get("bottom") ?? defaultPadding,
      left: this.externalScaleDimensions.get("left") ?? defaultPadding
    };
    return padding;
  }
  /**
   * Update properties on slotted scale elements
   */
  updateScaleProperties(padding) {
    const yMin = this.chart?.scales["y"]?.min ?? 0;
    const yMax = this.chart?.scales["y"]?.max ?? 100;
    const xMin = this.chart?.scales["x"]?.min ?? 0;
    const xMax = this.chart?.scales["x"]?.max ?? 100;
    const effectiveWidth = this.getEffectiveWidth();
    const effectiveHeight = this.getEffectiveHeight();
    const showLabels = effectiveWidth >= RECTANGULAR_CHART_DIMENSIONS.MIN_HEIGHT_WITH_LABELS && effectiveHeight >= RECTANGULAR_CHART_DIMENSIONS.MIN_HEIGHT_WITH_LABELS;
    const verticalViewBoxPadding = this.fixedAspectRatioScaling ? {
      top: Math.round(
        padding.top * this.scaleReferenceSize / this.height
      ),
      bottom: Math.round(
        padding.bottom * this.scaleReferenceSize / this.height
      )
    } : { top: padding.top, bottom: padding.bottom };
    const horizontalViewBoxPadding = this.fixedAspectRatioScaling ? {
      left: Math.round(
        padding.left * this.scaleReferenceSize / this.width
      ),
      right: Math.round(
        padding.right * this.scaleReferenceSize / this.width
      )
    } : { left: padding.left, right: padding.right };
    const updates = [];
    if (this.leftScaleSlot) {
      const scales = this.leftScaleSlot.assignedElements();
      scales.forEach((scale) => {
        const props = {
          minValue: yMin,
          maxValue: yMax,
          height: effectiveHeight,
          // Use effective height for proper sizing
          paddingTop: verticalViewBoxPadding.top,
          paddingBottom: verticalViewBoxPadding.bottom,
          paddingStart: verticalViewBoxPadding.top,
          paddingEnd: verticalViewBoxPadding.bottom,
          showLabels,
          fixedAspectRatio: this.fixedAspectRatioScaling,
          // Use chart's scaleReferenceSize property for proportional scaling
          scaleReferenceSize: this.scaleReferenceSize,
          state: this.state,
          priority: this.priority,
          frameStyle: this.frameStyle,
          borderRadiusPosition: this.borderRadiusPositionExternalScales
        };
        if (this.yStepSize !== void 0) {
          props.primaryTickmarkInterval = this.yStepSize;
        }
        updates.push([this.leftScaleSlot, scale, props]);
      });
    }
    if (this.rightScaleSlot) {
      const scales = this.rightScaleSlot.assignedElements();
      scales.forEach((scale) => {
        const props = {
          minValue: yMin,
          maxValue: yMax,
          height: effectiveHeight,
          // Use effective height for proper sizing
          paddingTop: verticalViewBoxPadding.top,
          paddingBottom: verticalViewBoxPadding.bottom,
          paddingStart: verticalViewBoxPadding.top,
          paddingEnd: verticalViewBoxPadding.bottom,
          showLabels,
          fixedAspectRatio: this.fixedAspectRatioScaling,
          // Use chart's scaleReferenceSize property for proportional scaling
          scaleReferenceSize: this.scaleReferenceSize,
          state: this.state,
          priority: this.priority,
          frameStyle: this.frameStyle,
          borderRadiusPosition: this.borderRadiusPositionExternalScales
        };
        if (this.yStepSize !== void 0) {
          props.primaryTickmarkInterval = this.yStepSize;
        }
        updates.push([this.rightScaleSlot, scale, props]);
      });
    }
    if (this.topScaleSlot) {
      const scales = this.topScaleSlot.assignedElements();
      scales.forEach((scale) => {
        const props = {
          minValue: xMin,
          maxValue: xMax,
          width: effectiveWidth,
          // Use effective width for proper sizing
          paddingLeft: horizontalViewBoxPadding.left,
          paddingRight: horizontalViewBoxPadding.right,
          paddingStart: horizontalViewBoxPadding.left,
          paddingEnd: horizontalViewBoxPadding.right,
          showLabels,
          fixedAspectRatio: this.fixedAspectRatioScaling,
          // Use chart's scaleReferenceSize property for proportional scaling
          scaleReferenceSize: this.scaleReferenceSize,
          state: this.state,
          priority: this.priority,
          frameStyle: this.frameStyle,
          borderRadiusPosition: this.borderRadiusPositionExternalScales
        };
        if (this.xStepSize !== void 0) {
          props.primaryTickmarkInterval = this.xStepSize;
        }
        updates.push([this.topScaleSlot, scale, props]);
      });
    }
    if (this.bottomScaleSlot) {
      const scales = this.bottomScaleSlot.assignedElements();
      scales.forEach((scale) => {
        const props = {
          minValue: xMin,
          maxValue: xMax,
          width: effectiveWidth,
          // Use effective width for proper sizing
          paddingLeft: horizontalViewBoxPadding.left,
          paddingRight: horizontalViewBoxPadding.right,
          paddingStart: horizontalViewBoxPadding.left,
          paddingEnd: horizontalViewBoxPadding.right,
          showLabels,
          fixedAspectRatio: this.fixedAspectRatioScaling,
          // Use chart's scaleReferenceSize property for proportional scaling
          scaleReferenceSize: this.scaleReferenceSize,
          state: this.state,
          priority: this.priority,
          frameStyle: this.frameStyle,
          borderRadiusPosition: this.borderRadiusPositionExternalScales
        };
        if (this.xStepSize !== void 0) {
          props.primaryTickmarkInterval = this.xStepSize;
        }
        updates.push([this.bottomScaleSlot, scale, props]);
      });
    }
    updates.forEach(([_slot, scale, props]) => {
      Object.assign(scale, props);
    });
  }
  hasAnyChanged(changed, props) {
    return props.some((prop) => changed.has(prop));
  }
  /**
   * Apply fillMode rules to datasets. Must be called after the chart is created
   * so scales and pixel coordinates are available for gradient construction.
   *
   * NOTE: For non-threshold modes (solid, semitransparent), backgroundColor is already
   * set correctly in buildDataset(). This method now only handles threshold gradients
   * which require Chart.js scales to be available.
   */
  applyFillModes() {
    if (!this.chart || !this.canvasEl || !this.canvasEl.isConnected) return;
    const chart = this.chart;
    const ctx = chart.ctx;
    if (!ctx) return;
    const fill = this.shouldApplyFill();
    const fillMode = this.getFillMode();
    if (fillMode !== "threshold" || !fill) {
      return;
    }
    chart.data.datasets.forEach((ds, _idx) => {
      const dataset = ds;
      if (dataset.fill === false || !fill) {
        return;
      }
      const yScaleId = dataset.yAxisID ?? "y";
      const yScale = chart.scales[yScaleId];
      if (!yScale) {
        return;
      }
      const dataValues = dataset.data.map((d) => typeof d === "number" ? d : d.y).filter((v) => Number.isFinite(v));
      if (dataValues.length === 0) {
        return;
      }
      const minVal = Math.min(...dataValues);
      const maxVal = Math.max(...dataValues);
      const thresholdVal = (minVal + maxVal) / 2;
      const thresholdPixel = yScale.getPixelForValue(thresholdVal);
      const range = yScale.bottom - yScale.top;
      let stop = (thresholdPixel - yScale.top) / range;
      if (!Number.isFinite(stop) || range === 0) {
        stop = 0.5;
      } else {
        stop = Math.max(0, Math.min(1, stop));
      }
      const lowRaw = LINE_GRAPH_GRID_CONFIG.thresholdLowColorVar;
      const highRaw = LINE_GRAPH_GRID_CONFIG.thresholdHighColorVar;
      const createGradient = (lowAlpha, highAlpha) => {
        const low = applyAlphaToColor(this, lowRaw, lowAlpha);
        const high = applyAlphaToColor(this, highRaw, highAlpha);
        const grad = ctx.createLinearGradient(0, yScale.top, 0, yScale.bottom);
        grad.addColorStop(0, high);
        grad.addColorStop(stop, high);
        grad.addColorStop(stop, low);
        grad.addColorStop(1, low);
        return grad;
      };
      const fillGradient = createGradient(0.35, 0.35);
      const borderGradient = createGradient(0.8, 0.8);
      dataset.backgroundColor = fillGradient;
      dataset.borderColor = borderGradient;
    });
  }
  // Update external library AFTER render
  updated(changed) {
    super.updated(changed);
    if (!this.hasAnyChanged(changed, LINE_GRAPH_WATCHED_PROP_NAMES)) {
      return;
    }
    const needsRecreation = this.hasAnyChanged(
      changed,
      LINE_GRAPH_RECREATE_PROP_NAMES
    );
    if (needsRecreation) {
      this.chart?.destroy();
      this.createChart();
    } else {
      this.updateChart();
    }
  }
  async firstUpdated() {
    await this.waitForScaleDimensions();
    if (!this.hasExternalScales()) {
      this.createChart();
    }
    this.themeObserver = observeThemeChanges(() => {
      this.updateChartColors();
      this.updateBorderRadius();
    });
    this.setupResizeObserver();
    this.setupAspectRatioResizeObserver();
    if (this.canvasEl) {
      if (!this.instrumentMode) {
        this.borderRadiusObserver = startExternalScaleBorderRadiusObserver(
          this.canvasEl,
          this.updateBorderRadius
        );
      }
      this.updateBorderRadius();
    }
  }
  disconnectedCallback() {
    super.disconnectedCallback();
    this.chart?.destroy();
    this.themeObserver?.disconnect();
    this.resizeObserver?.disconnect();
    this.aspectRatioResizeObserver?.disconnect();
    this.borderRadiusObserver?.disconnect();
    if (this.dimensionUpdateTimer) {
      clearTimeout(this.dimensionUpdateTimer);
    }
  }
  /**
   * Setup resize observer to detect height threshold crossings
   * Recreates chart when crossing MIN_HEIGHT_WITH_LABELS (192px) to show/hide labels
   * Detect when height property changes programmatically (e.g., via Storybook controls or user code)
   */
  setupResizeObserver() {
    if (!this.canvasEl) return;
    this.resizeObserver = new ResizeObserver(() => {
      if (!this.chart || !this.canvasEl || !this.canvasEl.isConnected) return;
      const height2 = this.canvasEl.clientHeight;
      const isAboveThreshold = height2 >= RECTANGULAR_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 >= RECTANGULAR_CHART_DIMENSIONS.MIN_HEIGHT_WITH_LABELS;
  }
  /**
   * Setup resize observer for fixed aspect ratio scaling.
   * Observes the wrapper element and recalculates dimensions when parent size changes.
   */
  setupAspectRatioResizeObserver() {
    const wrapper = this.renderRoot.querySelector(".wrapper");
    if (!wrapper) return;
    this.updateComputedDimensions();
    this.aspectRatioResizeObserver = new ResizeObserver(() => {
      if (!this.fixedAspectRatioScaling) return;
      this.updateComputedDimensions();
    });
    this.aspectRatioResizeObserver.observe(wrapper);
  }
  /**
   * Calculate actual dimensions based on parent width and aspect ratio.
   * Only used when fixedAspectRatioScaling is true.
   */
  updateComputedDimensions() {
    if (!this.fixedAspectRatioScaling) {
      this.computedWidth = this.width;
      this.computedHeight = this.height;
      return;
    }
    const wrapper = this.renderRoot.querySelector(".wrapper");
    if (!wrapper) return;
    const parentWidth = wrapper.clientWidth;
    if (parentWidth <= 0) return;
    const aspectRatio = this.width / this.height;
    const newWidth = parentWidth;
    const newHeight = Math.round(parentWidth / aspectRatio);
    if (this.computedWidth !== newWidth || this.computedHeight !== newHeight) {
      this.computedWidth = newWidth;
      this.computedHeight = newHeight;
      if (this.hasExternalScales()) {
        this.syncScalesAndChart();
      } else if (this.chart) {
        this.chart.destroy();
        this.createChart();
      }
    }
  }
  /**
   * Get the effective width for chart rendering.
   * Returns computed width when fixedAspectRatioScaling is true, otherwise the width property.
   */
  getEffectiveWidth() {
    return this.fixedAspectRatioScaling ? this.computedWidth : this.width;
  }
  /**
   * Get the effective height for chart rendering.
   * Returns computed height when fixedAspectRatioScaling is true, otherwise the height property.
   */
  getEffectiveHeight() {
    return this.fixedAspectRatioScaling ? this.computedHeight : this.height;
  }
  /**
   * Get the scale factor for proportional scaling when fixedAspectRatioScaling is true.
   * Returns 1.0 when not in fixed aspect ratio mode.
   * The scale factor is based on computed width vs reference width (the width property).
   */
  getScaleFactor() {
    if (!this.fixedAspectRatioScaling) {
      return 1;
    }
    return this.computedWidth / this.width;
  }
  /**
   * Build a complete dataset configuration with all styling properties.
   * Handles both new datasets (from values array) and existing datasets (normalization).
   *
   * @param data - Either numeric values array or existing dataset to normalize
   * @param index - Dataset index for color cycling
   * @param chartColors - Color palette array
   * @param totalCount - Total number of datasets (used for stacked divider logic)
   * @returns Fully configured Chart.js dataset
   */
  buildDataset(data, index, chartColors, totalCount = 1) {
    const currentColor = chartColors[index % chartColors.length];
    const existingDataset = "data" in data ? data : null;
    const values = existingDataset ? null : data;
    const borderColor = existingDataset?.borderColor ?? currentColor;
    const fillFlag = existingDataset?.fill ?? this.shouldApplyFill();
    const tension = this.lineMode === "smooth" ? this.DEFAULT_TENSION : 0;
    const isStacked = this.shouldStack() && this.getFillMode() !== "threshold";
    const needsDivider = isStacked && index < totalCount - 1;
    let backgroundColor = "transparent";
    const fillMode = this.getFillMode();
    if (fillFlag && fillMode) {
      const nextColor = chartColors[(index + 1) % chartColors.length];
      if (fillMode === "solid") {
        backgroundColor = String(borderColor);
      } else if (fillMode === "semitransparent") {
        backgroundColor = applyAlphaToColor(this, nextColor, 0.5);
      } else if (fillMode === "threshold") {
        backgroundColor = applyAlphaToColor(this, nextColor, 0.5);
      }
    }
    const result = {
      ...existingDataset || {},
      data: existingDataset?.data ?? values,
      borderColor,
      backgroundColor,
      borderWidth: existingDataset?.borderWidth ?? 2,
      showLine: existingDataset?.showLine ?? true,
      tension: existingDataset?.tension ?? tension,
      pointRadius: existingDataset?.pointRadius ?? (this.showPoints ? this.POINT_RADIUS : 0),
      pointBackgroundColor: existingDataset?.pointBackgroundColor ?? "#fff",
      pointBorderColor: existingDataset?.pointBorderColor ?? borderColor,
      pointBorderWidth: existingDataset?.pointBorderWidth ?? 2,
      stepped: existingDataset?.stepped ?? this.lineMode === "stepped",
      // Use 'start' to fill from chart bottom, not 'origin' (y=0)
      fill: fillFlag ? "start" : false,
      spanGaps: existingDataset?.spanGaps ?? true,
      // Add segment styling for stacked divider lines
      ...needsDivider && {
        segment: {
          borderColor: getCssVariableValue(
            this,
            LINE_GRAPH_GRID_CONFIG.stackedDividerColorVar
          ),
          borderWidth: 1
        }
      }
    };
    return result;
  }
  /**
   * Create threshold mode datasets: invisible baseline + main dataset with above/below fills
   */
  createThresholdDatasets(values, chartColors) {
    const numericValues = values.map((v) => Number(v)).filter((n) => Number.isFinite(n));
    const minV = numericValues.length ? Math.min(...numericValues) : 0;
    const maxV = numericValues.length ? Math.max(...numericValues) : 100;
    const threshold = (minV + maxV) / 2;
    const baselineData = numericValues.map(() => threshold);
    const lowRaw = LINE_GRAPH_GRID_CONFIG.thresholdLowColorVar;
    const highRaw = LINE_GRAPH_GRID_CONFIG.thresholdHighColorVar;
    const highFill = applyAlphaToColor(this, highRaw, 0.35);
    const lowFill = applyAlphaToColor(this, lowRaw, 0.35);
    const baselineDataset = {
      label: "threshold-baseline",
      data: baselineData,
      borderColor: "transparent",
      backgroundColor: "transparent",
      borderWidth: 0,
      pointRadius: 0,
      showLine: false,
      fill: false,
      spanGaps: true
    };
    const main = this.buildDataset(values, 0, chartColors);
    main.fill = {
      target: 0,
      above: highFill,
      below: lowFill
    };
    main.borderWidth = 2;
    return [baselineDataset, main];
  }
  /**
   * Prepare normalized datasets for multi-series charts
   */
  prepareMultiSeriesDatasets() {
    const defaultPalette = this.priority === Priority.enhanced ? CHART_SECTOR_ENHANCED_COLORS : CHART_SECTOR_DEFAULT_COLORS;
    const chartColors = getChartColorsOrDefault(
      this,
      this.colors,
      defaultPalette
    );
    const totalCount = this.datasets.length;
    return this.datasets.map(
      (ds, i) => this.buildDataset(ds, i, chartColors, totalCount)
    );
  }
  /**
   * Prepare datasets for single-series charts
   * Handles both regular and threshold fill modes
   */
  prepareSingleSeriesDatasets() {
    const values = this.data.map((d) => d.value);
    const labels = this.data.map((d) => d.label);
    const defaultPalette = this.priority === Priority.enhanced ? CHART_SECTOR_ENHANCED_COLORS : CHART_SECTOR_DEFAULT_COLORS;
    const chartColors = getChartColorsOrDefault(
      this,
      this.colors,
      defaultPalette
    );
    const fill = this.shouldApplyFill();
    const fillMode = this.getFillMode();
    const datasets = fill && fillMode === "threshold" ? this.createThresholdDatasets(values, chartColors) : [this.buildDataset(values, 0, chartColors)];
    return { datasets, labels };
  }
  /**
   * Get Chart.js options with dynamic sizing and padding
   */
  getChartOptions() {
    const effectiveWidth = this.getEffectiveWidth();
    const effectiveHeight = this.getEffectiveHeight();
    const isTooSmall = effectiveWidth < RECTANGULAR_CHART_DIMENSIONS.MIN_HEIGHT_WITH_LABELS || effectiveHeight < RECTANGULAR_CHART_DIMENSIONS.MIN_HEIGHT_WITH_LABELS;
    const scaleFactor = this.getScaleFactor();
    let padding;
    if (isTooSmall) {
      padding = { top: 0, right: 0, bottom: 0, left: 0 };
    } else if (this.hasExternalScales()) {
      const scalePadding = this.calculatePaddingFromScales();
      const defaultPaddingScaled = this.fixedAspectRatioScaling ? Math.round(CHART_DIMENSIONS.CANVAS_PADDING * scaleFactor) : CHART_DIMENSIONS.CANVAS_PADDING;
      padding = {
        top: this.externalScaleDimensions.has("top") ? scalePadding.top : defaultPaddingScaled,
        right: this.externalScaleDimensions.has("right") ? scalePadding.right : defaultPaddingScaled,
        bottom: this.externalScaleDimensions.has("bottom") ? scalePadding.bottom : defaultPaddingScaled,
        left: this.externalScaleDimensions.has("left") ? scalePadding.left : defaultPaddingScaled
      };
    } else {
      const defaultPaddingScaled = this.fixedAspectRatioScaling ? Math.round(CHART_DIMENSIONS.CANVAS_PADDING * scaleFactor) : CHART_DIMENSIONS.CANVAS_PADDING;
      padding = {
        top: defaultPaddingScaled,
        right: defaultPaddingScaled,
        bottom: defaultPaddingScaled,
        left: defaultPaddingScaled
      };
    }
    if (this.fixedAspectRatioScaling) {
      this.style.setProperty("--chart-width", "100%");
      this.style.setProperty("--chart-height", `${effectiveHeight}px`);
    } else {
      this.style.setProperty("--chart-width", `${this.width}px`);
      this.style.setProperty("--chart-height", `${this.height}px`);
    }
    const refTs = this.computeTimeReference();
    const effectiveShowTickMarks = this.hasExternalScales() ? false : this.showTickMarks;
    return {
      responsive: true,
      maintainAspectRatio: false,
      // Use explicit width/height instead
      layout: {
        padding
      },
      plugins: {
        legend: {
          display: false,
          labels: {
            generateLabels: () => []
            // Prevent Chart.js from generating labels internally
          },
          onClick: () => {
          }
          // Disable legend click handler
        },
        tooltip: {
          ...getChartTooltipOptions(this),
          enabled: !isTooSmall,
          callbacks: {
            title: () => "",
            label: (context) => {
              const label = context.label ?? "";
              const value = typeof context.parsed === "object" && context.parsed !== null ? context.parsed.y : context.parsed;
              const numericValue = formatNumericValue(value, 1, false, 0);
              const unit = this.unit ? `${this.unit}` : "";
              return `${label} ${numericValue}${unit}`;
            }
          }
        }
      },
      animation: false,
      scales: this.buildScalesConfig(refTs, isTooSmall, effectiveShowTickMarks)
    };
  }
  /**
   * Compute reference timestamp for time axis formatting.
   * Returns earliest timestamp for 'date' mode, latest for 'minutes' mode.
   */
  computeTimeReference() {
    const timestamps = [];
    if (this.datasets?.length) {
      this.datasets.forEach((ds) => {
        if (!ds.data) return;
        ds.data.forEach((pt) => {
          if (pt && typeof pt === "object" && "x" in pt) {
            const xVal = pt.x;
            const ts = typeof xVal === "string" ? new Date(String(xVal)).getTime() : Number(xVal);
            if (Number.isFinite(ts)) timestamps.push(ts);
          }
        });
      });
    }
    if (!timestamps.length && this.labels?.length) {
      this.labels.forEach((l) => {
        if (typeof l === "string") {
          const ts = new Date(l).getTime();
          if (Number.isFinite(ts)) timestamps.push(ts);
        }
      });
    }
    return timestamps.length ? this.timeDisplay === "minutes" ? Math.max(...timestamps) : Math.min(...timestamps) : void 0;
  }
  /**
   * Build Chart.js scale configuration with theme-aware styling.
   * Applies CSS variables for grid colors, tick colors, and label typography.
   *
   * @param minX - Reference timestamp for time-based x-axis (used for 'minutes' display)
   * @param isTooSmall - Whether chart is below 192px threshold (hides ticks when true)
   * @param showTickMarks - Whether to show tick marks (overridden to false when external scales present)
   * @returns Configured scales object for Chart.js options
   */
  buildScalesConfig(minX, isTooSmall = false, showTickMarks = true) {
    const gridColor = getCssVariableValue(
      this,
      LINE_GRAPH_GRID_CONFIG.gridColorVar
    );
    const tickColor = getCssVariableValue(
      this,
      LINE_GRAPH_GRID_CONFIG.tickColorVar
    );
    const fontFamily = getCssVariableValue(
      this,
      LINE_GRAPH_LABEL_CONFIG.fontFamily
    );
    const fontSize = getCssVariableValue(
      this,
      LINE_GRAPH_LABEL_CONFIG.fontSizeVar
    );
    const fontWeight = getCssVariableValue(
      this,
      LINE_GRAPH_LABEL_CONFIG.fontWeightVar
    );
    const fontColor = getCssVariableValue(
      this,
      LINE_GRAPH_LABEL_CONFIG.fontColorVar
    );
    const showLabels = showTickMarks && !isTooSmall;
    const showTicks = showTickMarks && !isTooSmall;
    const fontConfig = { family: fontFamily, size: fontSize, weight: fontWeight };
    const x = {
      type: this.xAxisType === "time" ? "linear" : "category",
      offset: false,
      // Always edge-to-edge (no padding on x-axis)
      grace: 0,
      // No extra margin
      bounds: "data",
      // Use data bounds for edge-to-edge rendering
      grid: {
        display: this.showGrid && this.showGridX,
        color: gridColor,
        offset: false,
        drawTicks: showTicks
      },
      ticks: {
        display: showLabels,
        color: fontColor,
        font: fontConfig,
        maxRotation: 0,
        // Keep labels horizontal (no rotation)
        minRotation: 0,
        // Keep labels horizontal (no rotation)
        maxTicksLimit: this.xTicksLimit,
        stepSize: this.xStepSize,
        callback: (value) => {
          if (this.xAxisType !== "time") return String(value);
          const n = Number(value);
          if (!Number.isFinite(n)) return String(value);
          if (this.timeDisplay === "minutes" && minX !== void 0 && Number.isFinite(minX)) {
            const minutes = Math.round((n - minX) / 6e4);
            return `${minutes}min`;
          }
          return new Date(n).toLocaleDateString();
        }
      },
      border: {
        display: showLabels,
        color: tickColor
      }
    };
    const yAxesConfig = this.yAxes?.length ? this.yAxes.map((axis, i) => ({
      id: axis.id ?? `y${i}`,
      position: axis.position ?? "left",
      min: axis.min,
      max: axis.max,
      gridDisplay: axis.grid ?? (this.showGrid && this.showGridY)
    })) : [
      {
        id: "y",
        position: this.yAxisPosition,
        min: void 0,
        max: void 0,
        gridDisplay: this.showGrid && this.showGridY
      }
    ];
    const scalesRecord = { x };
    yAxesConfig.forEach(({ id, position, min, max, gridDisplay }) => {
      scalesRecord[id] = {
        type: "linear",
        display: true,
        position,
        stacked: this.shouldStack() && this.getFillMode() !== "threshold",
        grace: isTooSmall ? 0 : void 0,
        bounds: isTooSmall ? "data" : "ticks",
        grid: {
          display: gridDisplay,
          color: gridColor,
          drawTicks: showTicks
        },
        ticks: {
          display: showLabels,
          color: fontColor,
          font: fontConfig,
          maxTicksLimit: this.yTicksLimit,
          stepSize: this.yStepSize
        },
        border: {
          display: showLabels,
          color: tickColor
        },
        min,
        max
      };
    });
    return scalesRecord;
  }
  /**
   * Prepare chart data and labels for both single and multi-series modes
   */
  prepareChartDataAndLabels() {
    if (this.datasets?.length) {
      return {
        datasets: this.prepareMultiSeriesDatasets(),
        labels: this.labels ?? []
      };
    }
    return this.prepareSingleSeriesDatasets();
  }
  createChart() {
    if (!this.canvasEl || !this.canvasEl.isConnected) return;
    const ctx = this.canvasEl.getContext("2d");
    if (!ctx) return;
    if (this.chart) {
      this.chart.destroy();
      this.chart = void 0;
    }
    const { datasets, labels } = this.prepareChartDataAndLabels();
    this.chart = new Chart(ctx, {
      type: "line",
      data: { labels, datasets },
      options: this.getChartOptions(),
      plugins: this.borderRadiusPosition ? [this.createBorderPlugin()] : []
    });
    requestAnimationFrame(() => this.updateLegend());
    this.applyFillModes();
  }
  updateChart() {
    if (!this.chart || !this.canvasEl || !this.canvasEl.isConnected) return;
    const { datasets, labels } = this.prepareChartDataAndLabels();
    this.chart.data.labels = labels;
    this.chart.data.datasets = datasets;
    Object.assign(this.chart.options, this.getChartOptions());
    this.applyFillModes();
    this.chart.update();
    requestAnimationFrame(() => this.updateLegend());
  }
  /**
   * Update only chart colors without recalculating layout
   * Used by theme observer for efficient theme changes
   */
  updateChartColors() {
    if (!this.chart || !this.canvasEl || !this.canvasEl.isConnected) return;
    this.applyFillModes();
    this.chart.update("none");
    requestAnimationFrame(() => this.updateLegend());
  }
  /**
   * Update the legend HTML content
   */
  updateLegend() {
    if (!this.legend || !this.legendDiv || !this.chart) return;
    if (!this.chart.data.datasets || this.chart.data.datasets.length === 0) {
      this.legendDiv.innerHTML = "";
      return;
    }
    try {
      const legendItems = this.chart.data.datasets.map((ds, i) => {
        const meta = this.chart.getDatasetMeta(i);
        if (!meta || !meta.controller) {
          return null;
        }
        const style = meta.controller.getStyle(0, false);
        const dataset = ds;
        return {
          fillStyle: dataset.borderColor ?? style.borderColor ?? "",
          label: dataset.label || `Series ${i + 1}`,
          value: "",
          unit: ""
        };
      }).filter((item) => item !== null);
      if (legendItems.length > 0) {
        const legendHTML = generateLegendHTML(legendItems);
        this.legendDiv.innerHTML = legendHTML;
      }
    } catch (error) {
      console.debug(
        "[chart-line-base] updateLegend: error generating legend HTML",
        error
      );
    }
  }
  render() {
    return html`
      <div class="wrapper">
        <div class="canvas-and-slots-container">
          <slot
            name="top-scale"
            @slotchange=${this.handleSlotChange}
            @scale-dimensions-changed=${this.handleScaleDimensionsChanged}
          ></slot>
          <slot
            name="bottom-scale"
            @slotchange=${this.handleSlotChange}
            @scale-dimensions-changed=${this.handleScaleDimensionsChanged}
          ></slot>
          <slot
            name="left-scale"
            @slotchange=${this.handleSlotChange}
            @scale-dimensions-changed=${this.handleScaleDimensionsChanged}
          ></slot>
          <slot
            name="right-scale"
            @slotchange=${this.handleSlotChange}
            @scale-dimensions-changed=${this.handleScaleDimensionsChanged}
          ></slot>
          <canvas></canvas>
        </div>

        ${this.legend ? html`<div class="legend"></div>` : ""}
      </div>
    `;
  }
};
_ObcChartLineBase.styles = [
  unsafeCSS(componentStyle),
  unsafeCSS(chartCommonStyle),
  unsafeCSS(chartLegendStyle),
  unsafeCSS(chartDebugStyle)
];
let ObcChartLineBase = _ObcChartLineBase;
__decorateClass([
  property({ attribute: false })
], ObcChartLineBase.prototype, "data");
__decorateClass([
  property({ attribute: false })
], ObcChartLineBase.prototype, "datasets");
__decorateClass([
  property({ attribute: false })
], ObcChartLineBase.prototype, "labels");
__decorateClass([
  property({ attribute: false })
], ObcChartLineBase.prototype, "colors");
__decorateClass([
  property({ type: Boolean, reflect: true })
], ObcChartLineBase.prototype, "legend");
__decorateClass([
  property({ type: Boolean, reflect: true })
], ObcChartLineBase.prototype, "showDebugOverlay");
__decorateClass([
  property({ type: Number, reflect: true })
], ObcChartLineBase.prototype, "width");
__decorateClass([
  property({ type: Number, reflect: true })
], ObcChartLineBase.prototype, "height");
__decorateClass([
  property({ type: Boolean, reflect: true })
], ObcChartLineBase.prototype, "fixedAspectRatioScaling");
__decorateClass([
  property({ type: Number })
], ObcChartLineBase.prototype, "scaleReferenceSize");
__decorateClass([
  property({ type: String })
], ObcChartLineBase.prototype, "xAxisType");
__decorateClass([
  property({ type: String })
], ObcChartLineBase.prototype, "yAxisPosition");
__decorateClass([
  property({ attribute: false })
], ObcChartLineBase.prototype, "yAxes");
__decorateClass([
  property({ type: Boolean })
], ObcChartLineBase.prototype, "showGrid");
__decorateClass([
  property({ type: Boolean })
], ObcChartLineBase.prototype, "showGridX");
__decorateClass([
  property({ type: Boolean })
], ObcChartLineBase.prototype, "showGridY");
__decorateClass([
  property({ type: Boolean })
], ObcChartLineBase.prototype, "showTickMarks");
__decorateClass([
  property({ type: Boolean })
], ObcChartLineBase.prototype, "showPoints");
__decorateClass([
  property({ type: String })
], ObcChartLineBase.prototype, "lineMode");
__decorateClass([
  property({ type: String })
], ObcChartLineBase.prototype, "unit");
__decorateClass([
  property({ type: String })
], ObcChartLineBase.prototype, "timeDisplay");
__decorateClass([
  property({ type: Number })
], ObcChartLineBase.prototype, "xTicksLimit");
__decorateClass([
  property({ type: Number })
], ObcChartLineBase.prototype, "xStepSize");
__decorateClass([
  property({ type: Number })
], ObcChartLineBase.prototype, "yTicksLimit");
__decorateClass([
  property({ type: Number })
], ObcChartLineBase.prototype, "yStepSize");
__decorateClass([
  property({ type: String })
], ObcChartLineBase.prototype, "state");
__decorateClass([
  property({ type: String })
], ObcChartLineBase.prototype, "priority");
__decorateClass([
  property({ type: String })
], ObcChartLineBase.prototype, "frameStyle");
__decorateClass([
  property({ type: String })
], ObcChartLineBase.prototype, "borderRadiusPosition");
__decorateClass([
  property({ type: String })
], ObcChartLineBase.prototype, "borderRadiusPositionExternalScales");
__decorateClass([
  property({ type: Boolean })
], ObcChartLineBase.prototype, "instrumentMode");
__decorateClass([
  property({ type: Number })
], ObcChartLineBase.prototype, "borderRadius");
__decorateClass([
  query("canvas")
], ObcChartLineBase.prototype, "canvasEl");
__decorateClass([
  query(".legend")
], ObcChartLineBase.prototype, "legendDiv");
__decorateClass([
  query('slot[name="top-scale"]')
], ObcChartLineBase.prototype, "topScaleSlot");
__decorateClass([
  query('slot[name="bottom-scale"]')
], ObcChartLineBase.prototype, "bottomScaleSlot");
__decorateClass([
  query('slot[name="left-scale"]')
], ObcChartLineBase.prototype, "leftScaleSlot");
__decorateClass([
  query('slot[name="right-scale"]')
], ObcChartLineBase.prototype, "rightScaleSlot");
export {
  LineMode,
  ObcChartLineBase,
  TimeDisplay,
  XAxisType,
  YAxisPosition
};
//# sourceMappingURL=chart-line-base.js.map
