(function initPortfolioSharedComponents(global) {
  const PIE_CHART_PALETTE = [
    '#43d0b4', '#4a9de0', '#f4a259', '#e8697d', '#9b8ade',
    '#5fc9a3', '#f2c14e', '#7fa6d9', '#d98cb3', '#6fd3d8',
    '#c1d95f', '#e07a5f', '#8fb8de', '#b5a7e6', '#59c2c9'
  ];

  const verticalMarkerLinesPlugin = {
    id: 'verticalMarkerLines',
    beforeDatasetsDraw(chart) {
      const pluginOptions = chart.config.options.plugins && chart.config.options.plugins.verticalMarkerLines;
      const lines = pluginOptions && Array.isArray(pluginOptions.lines) ? pluginOptions.lines : [];
      chart.$verticalMarkerLabelBoxes = [];
      if (lines.length === 0) {
        return;
      }

      const { ctx, chartArea, scales } = chart;
      const xScale = scales && scales.x;
      if (!ctx || !chartArea || !xScale) {
        return;
      }

      function clamp(value, min, max) {
        return Math.min(Math.max(value, min), max);
      }

      function drawRoundedRect(ctx2d, x, y, width, height, radius) {
        const r = Math.max(0, Math.min(radius, Math.floor(Math.min(width, height) / 2)));
        ctx2d.beginPath();
        ctx2d.moveTo(x + r, y);
        ctx2d.lineTo(x + width - r, y);
        ctx2d.quadraticCurveTo(x + width, y, x + width, y + r);
        ctx2d.lineTo(x + width, y + height - r);
        ctx2d.quadraticCurveTo(x + width, y + height, x + width - r, y + height);
        ctx2d.lineTo(x + r, y + height);
        ctx2d.quadraticCurveTo(x, y + height, x, y + height - r);
        ctx2d.lineTo(x, y + r);
        ctx2d.quadraticCurveTo(x, y, x + r, y);
        ctx2d.closePath();
      }

      ctx.save();
      lines.forEach((line) => {
        const x = xScale.getPixelForValue(line.index);
        if (!Number.isFinite(x)) {
          return;
        }

        ctx.beginPath();
        ctx.strokeStyle = line.color || 'rgba(255, 255, 255, 0.2)';
        ctx.lineWidth = line.lineWidth || 1;
        ctx.moveTo(x, chartArea.top);
        ctx.lineTo(x, chartArea.bottom);
        ctx.stroke();

        const label = typeof line.label === 'string' ? line.label.trim() : '';
        if (!label) {
          return;
        }

        const paddingX = Number.isFinite(Number(line.labelPaddingX)) ? Number(line.labelPaddingX) : 5;
        const boxHeight = Number.isFinite(Number(line.labelHeight)) ? Number(line.labelHeight) : 16;
        const yOffset = Number.isFinite(Number(line.labelYOffset)) ? Number(line.labelYOffset) : 6;
        const maxY = chart.height - boxHeight - 2;
        const boxY = clamp(chartArea.bottom + yOffset, chartArea.bottom + 2, maxY);

        ctx.font = line.labelFont || '600 10px sans-serif';
        const textWidth = ctx.measureText(label).width;
        const boxWidth = textWidth + (paddingX * 2);
        const boxX = clamp(x - (boxWidth / 2), chartArea.left + 2, chartArea.right - boxWidth - 2);
        const borderRadius = Number.isFinite(Number(line.labelBorderRadius)) ? Number(line.labelBorderRadius) : 4;

        drawRoundedRect(ctx, boxX, boxY, boxWidth, boxHeight, borderRadius);
        ctx.fillStyle = line.labelBackgroundColor || line.color || 'rgba(255, 255, 255, 0.65)';
        ctx.fill();

        drawRoundedRect(ctx, boxX, boxY, boxWidth, boxHeight, borderRadius);
        ctx.strokeStyle = line.labelBorderColor || 'rgba(16, 33, 46, 0.45)';
        ctx.lineWidth = 1;
        ctx.stroke();

        ctx.fillStyle = line.labelTextColor || '#10212e';
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';
        ctx.fillText(label, boxX + (boxWidth / 2), boxY + (boxHeight / 2));

        chart.$verticalMarkerLabelBoxes.push({
          x: boxX,
          y: boxY,
          width: boxWidth,
          height: boxHeight,
          index: line.index
        });
      });
      ctx.restore();
    }
  };

  if (typeof global.Chart === 'function' && typeof global.Chart.register === 'function') {
    global.Chart.register(verticalMarkerLinesPlugin);
  }

  const yearBoundaryMarkersPlugin = {
    id: 'yearBoundaryMarkers',
    afterDraw(chart) {
      const pluginOptions = chart.config.options.plugins && chart.config.options.plugins.yearBoundaryMarkers;
      const groups = pluginOptions && Array.isArray(pluginOptions.groups) ? pluginOptions.groups : [];
      const secondaryGroups = pluginOptions && Array.isArray(pluginOptions.secondaryGroups) ? pluginOptions.secondaryGroups : [];
      if (groups.length === 0 && secondaryGroups.length === 0) {
        return;
      }

      const { ctx, scales, chartArea, legend } = chart;
      const xScale = scales && scales.x;
      if (!ctx || !xScale) {
        return;
      }

      const color = pluginOptions.color || 'rgba(255, 255, 255, 0.4)';
      const textColor = pluginOptions.textColor || '#e6edf3';
      const lineWidth = pluginOptions.lineWidth || 1.5;
      const tickLength = 10;
      const rowOffset = Number.isFinite(Number(pluginOptions.rowOffset))
        ? Number(pluginOptions.rowOffset)
        : 0;
      const rowTopGap = Number.isFinite(Number(pluginOptions.rowTopGap))
        ? Number(pluginOptions.rowTopGap)
        : 8;
      const rowBottomGap = Number.isFinite(Number(pluginOptions.rowBottomGap))
        ? Number(pluginOptions.rowBottomGap)
        : 12;
      const labelLift = Number.isFinite(Number(pluginOptions.labelLift))
        ? Number(pluginOptions.labelLift)
        : 0;
      const edgeLabels = pluginOptions.edgeLabels && typeof pluginOptions.edgeLabels === 'object'
        ? pluginOptions.edgeLabels
        : null;
      const boundaryAlignDatasetIndex = Number.isFinite(Number(pluginOptions.boundaryAlignDatasetIndex))
        ? Number(pluginOptions.boundaryAlignDatasetIndex)
        : null;
      const boundaryAlignEdge = typeof pluginOptions.boundaryAlignEdge === 'string'
        ? String(pluginOptions.boundaryAlignEdge).toLowerCase()
        : 'center';

      function getBoundaryX(tickIndex) {
        const tickX = xScale.getPixelForValue(tickIndex);
        if (!Number.isFinite(tickX)) {
          return null;
        }

        if (!Number.isFinite(boundaryAlignDatasetIndex)) {
          return tickX;
        }

        const meta = typeof chart.getDatasetMeta === 'function'
          ? chart.getDatasetMeta(boundaryAlignDatasetIndex)
          : null;
        const dataPoint = meta && Array.isArray(meta.data) ? meta.data[tickIndex] : null;
        const barX = dataPoint && Number.isFinite(dataPoint.x) ? dataPoint.x : null;
        const barWidth = dataPoint && Number.isFinite(dataPoint.width) ? dataPoint.width : null;

        if (!Number.isFinite(barX)) {
          return tickX;
        }

        if (boundaryAlignEdge === 'right' && Number.isFinite(barWidth)) {
          return barX + (barWidth / 2);
        }

        if (boundaryAlignEdge === 'left' && Number.isFinite(barWidth)) {
          return barX - (barWidth / 2);
        }

        return barX;
      }

      function isSyntheticLeadingBoundaryGroup(group, groupIndex) {
        if (!group || groupIndex !== 0) {
          return false;
        }

        return group.label == null
          && group.labelStartIndex == null
          && group.labelEndIndex == null
          && Number(group.tickIndex) === 0;
      }

      function getGroupBoundaryX(group, groupIndex, options = {}) {
        const useChartLeftForFirstBoundary = options && options.useChartLeftForFirstBoundary === true;
        const shouldAnchorToChartLeft = isSyntheticLeadingBoundaryGroup(group, groupIndex)
          || (useChartLeftForFirstBoundary && groupIndex === 0);

        if (shouldAnchorToChartLeft && chartArea) {
          return chartArea.left;
        }

        return getBoundaryX(group && group.tickIndex);
      }

      function drawBoundaryGroups(boundaryGroups, y, boundaryTickLength = tickLength, labelOffset = 8, options = {}) {
        const useChartLeftForFirstBoundary = options && options.useChartLeftForFirstBoundary === true;
        boundaryGroups.forEach((group, groupIndex) => {
          const tickX = getGroupBoundaryX(group, groupIndex, options);
          if (!Number.isFinite(tickX)) {
            return;
          }

          ctx.beginPath();
          ctx.moveTo(tickX, y);
          ctx.lineTo(tickX, y + boundaryTickLength);
          ctx.stroke();

          if (group.label) {
            const previousGroup = groupIndex > 0 ? boundaryGroups[groupIndex - 1] : null;
            const hasSyntheticLeadingBoundary = previousGroup
              && isSyntheticLeadingBoundaryGroup(previousGroup, groupIndex - 1)
              && Number(group.labelStartIndex) === 0;
            const isFirstYearLabelInYearOnlyMode = useChartLeftForFirstBoundary
              && group.labelStartIndex === 0
              && groupIndex > 0;
            const labelStartX = hasSyntheticLeadingBoundary
              ? getGroupBoundaryX(previousGroup, groupIndex - 1, options)
              : (isFirstYearLabelInYearOnlyMode && chartArea
                ? chartArea.left
                : getBoundaryX(group.labelStartIndex));
            const labelEndX = getBoundaryX(group.labelEndIndex);
            if (Number.isFinite(labelStartX) && Number.isFinite(labelEndX)) {
              ctx.fillStyle = textColor;
              const insideY = y + Math.max(6, Math.floor(boundaryTickLength * 0.45));
              ctx.fillText(group.label, (labelStartX + labelEndX) / 2, insideY - labelLift);
            }
          }
        });
      }

      function clamp(value, min, max) {
        return Math.min(Math.max(value, min), max);
      }

      ctx.save();
      ctx.strokeStyle = color;
      ctx.lineWidth = lineWidth;
      ctx.font = 'bold 13px sans-serif';
      ctx.textAlign = 'center';
      ctx.textBaseline = 'middle';
      const baseY = chartArea ? chartArea.bottom : xScale.bottom;
      const secondaryTickLength = 20;
      const yearTickLength = tickLength;
      const rowGap = 10;
      const labelOffset = 8;
      const bottomReserve = rowBottomGap + yearTickLength + labelOffset + 8;
      const maxSecondaryY = chart.height - bottomReserve - secondaryTickLength - rowGap;
      const secondaryY = clamp(baseY + rowTopGap + rowOffset, 0, maxSecondaryY);
      const yearY = clamp(secondaryY + secondaryTickLength + rowGap, secondaryY + rowGap, chart.height - bottomReserve);
      if (secondaryGroups.length > 0) {
        drawBoundaryGroups(secondaryGroups, secondaryY, secondaryTickLength, labelOffset);
        drawBoundaryGroups(groups, yearY, yearTickLength, labelOffset);
      } else {
        drawBoundaryGroups(groups, secondaryY, secondaryTickLength, labelOffset, { useChartLeftForFirstBoundary: true });
      }

      if (edgeLabels && chartArea) {
        const edgeLabelY = legend ? legend.top + (legend.height / 2) : chartArea.top - 8;
        ctx.fillStyle = edgeLabels.color || textColor;
        ctx.font = '12px sans-serif';
        ctx.textBaseline = 'middle';

        if (edgeLabels.start) {
          ctx.textAlign = 'left';
          ctx.fillText(edgeLabels.start, chartArea.left, edgeLabelY);
        }

        if (edgeLabels.end) {
          ctx.textAlign = 'right';
          ctx.fillText(edgeLabels.end, chartArea.right, edgeLabelY);
        }
      }

      const secondaryTickPositions = secondaryGroups
        .map((group, groupIndex) => getGroupBoundaryX(group, groupIndex))
        .filter((tickX) => Number.isFinite(tickX));
      if (secondaryTickPositions.length > 1) {
        ctx.beginPath();
        ctx.moveTo(Math.min.apply(null, secondaryTickPositions), secondaryY + secondaryTickLength);
        ctx.lineTo(Math.max.apply(null, secondaryTickPositions), secondaryY + secondaryTickLength);
        ctx.stroke();
      }

      const secondaryTickIndices = new Set(secondaryGroups.map((group) => group.tickIndex));
      groups.forEach((group, groupIndex) => {
        if (!secondaryTickIndices.has(group.tickIndex)) {
          return;
        }

        const tickX = getGroupBoundaryX(group, groupIndex);
        if (!Number.isFinite(tickX)) {
          return;
        }

        ctx.beginPath();
  ctx.moveTo(tickX, secondaryY + secondaryTickLength);
        ctx.lineTo(tickX, yearY);
        ctx.stroke();
      });
      ctx.restore();
    }
  };

  if (typeof global.Chart === 'function' && typeof global.Chart.register === 'function') {
    global.Chart.register(yearBoundaryMarkersPlugin);
  }

  function BlockingScreenLoader({ isActive, title, message }) {
    if (!isActive) {
      return null;
    }

    return (
      <div className="screen-loading-overlay" role="status" aria-live="polite" aria-label={title || 'Loading'}>
        <div className="screen-loading-card">
          <span className="screen-loading-spinner" aria-hidden="true" />
          <strong>{title || 'Loading...'}</strong>
          <span className="muted">{message || 'Please wait.'}</span>
        </div>
      </div>
    );
  }

  function buildLineChartOptions(options) {    const baseOptions = {
      responsive: true,
      maintainAspectRatio: false,
      animation: false,
      interaction: {
        mode: 'index',
        intersect: false
      },
      plugins: {
        legend: {
          display: false
        }
      }
    };

    const customOptions = options && typeof options === 'object' ? options : {};
    return Object.assign({}, baseOptions, customOptions, {
      interaction: Object.assign({}, baseOptions.interaction, customOptions.interaction || {}),
      plugins: Object.assign({}, baseOptions.plugins, customOptions.plugins || {}),
      scales: Object.assign({}, customOptions.scales || {})
    });
  }

  function LineChart({ labels, datasets, options, className, ariaLabel, height }) {
    const canvasRef = React.useRef(null);
    const chartRef = React.useRef(null);
    const chartLibrary = global.Chart;

    React.useEffect(() => {
      if (!canvasRef.current || typeof chartLibrary !== 'function') {
        return undefined;
      }

      if (chartRef.current) {
        chartRef.current.destroy();
        chartRef.current = null;
      }

      const context = canvasRef.current.getContext('2d');
      if (!context) {
        return undefined;
      }

      const normalizedDatasets = (Array.isArray(datasets) ? datasets : []).map((dataset) => Object.assign({
        fill: false,
        tension: 0.25,
        pointRadius: 2.5,
        pointHoverRadius: 4,
        borderWidth: 2
      }, dataset || {}));

      chartRef.current = new chartLibrary(context, {
        type: 'line',
        data: {
          labels: Array.isArray(labels) ? labels : [],
          datasets: normalizedDatasets
        },
        options: buildLineChartOptions(options)
      });

      function resolveDatasetIndicesForPoint(dataIndex) {
        const chart = chartRef.current;
        if (!chart || !Array.isArray(chart.data && chart.data.datasets)) {
          return [];
        }

        const indices = [];
        for (let datasetIndex = 0; datasetIndex < chart.data.datasets.length; datasetIndex += 1) {
          const dataset = chart.data.datasets[datasetIndex] || {};
          const rows = Array.isArray(dataset.data) ? dataset.data : [];
          const value = Number(rows[dataIndex]);
          if (Number.isFinite(value)) {
            indices.push(datasetIndex);
          }
        }

        return indices;
      }

      function onCanvasClick(event) {
        const chart = chartRef.current;
        const canvas = canvasRef.current;
        if (!chart || !canvas) {
          return;
        }

        const labelBoxes = Array.isArray(chart.$verticalMarkerLabelBoxes)
          ? chart.$verticalMarkerLabelBoxes
          : [];
        if (labelBoxes.length === 0) {
          return;
        }

        const rect = canvas.getBoundingClientRect();
        const x = event.clientX - rect.left;
        const y = event.clientY - rect.top;
        const hitBox = labelBoxes.find((box) => (
          x >= box.x
          && x <= (box.x + box.width)
          && y >= box.y
          && y <= (box.y + box.height)
        ));
        if (!hitBox) {
          return;
        }

        const dataIndex = Number(hitBox.index);
        if (!Number.isFinite(dataIndex)) {
          return;
        }

        const datasetIndices = resolveDatasetIndicesForPoint(dataIndex);
        if (!Array.isArray(datasetIndices) || datasetIndices.length === 0) {
          return;
        }

        const activeElements = datasetIndices.map((datasetIndex) => ({ datasetIndex, index: dataIndex }));
        chart.setActiveElements(activeElements);
        if (chart.tooltip && typeof chart.tooltip.setActiveElements === 'function') {
          const xScale = chart.scales && chart.scales.x;
          const chartArea = chart.chartArea;
          const anchorX = xScale && Number.isFinite(xScale.getPixelForValue(dataIndex))
            ? xScale.getPixelForValue(dataIndex)
            : x;
          const anchorY = chartArea && Number.isFinite(chartArea.top)
            ? chartArea.top + 8
            : y;
          chart.tooltip.setActiveElements(activeElements, { x: anchorX, y: anchorY });
        }
        chart.update();
      }

      function onCanvasMouseMove(event) {
        const chart = chartRef.current;
        const canvas = canvasRef.current;
        if (!chart || !canvas) {
          return;
        }

        const labelBoxes = Array.isArray(chart.$verticalMarkerLabelBoxes)
          ? chart.$verticalMarkerLabelBoxes
          : [];
        if (labelBoxes.length === 0) {
          canvas.style.cursor = '';
          return;
        }

        const rect = canvas.getBoundingClientRect();
        const x = event.clientX - rect.left;
        const y = event.clientY - rect.top;
        const isHoveringBox = labelBoxes.some((box) => (
          x >= box.x
          && x <= (box.x + box.width)
          && y >= box.y
          && y <= (box.y + box.height)
        ));

        canvas.style.cursor = isHoveringBox ? 'pointer' : '';
      }

      function onCanvasMouseLeave() {
        if (canvasRef.current) {
          canvasRef.current.style.cursor = '';
        }
      }

      canvasRef.current.addEventListener('click', onCanvasClick);
      canvasRef.current.addEventListener('mousemove', onCanvasMouseMove);
      canvasRef.current.addEventListener('mouseleave', onCanvasMouseLeave);

      return () => {
        if (canvasRef.current) {
          canvasRef.current.removeEventListener('click', onCanvasClick);
          canvasRef.current.removeEventListener('mousemove', onCanvasMouseMove);
          canvasRef.current.removeEventListener('mouseleave', onCanvasMouseLeave);
        }
        if (chartRef.current) {
          chartRef.current.destroy();
          chartRef.current = null;
        }
      };
    }, [chartLibrary, labels, datasets, options]);

    if (typeof chartLibrary !== 'function') {
      return <p className="muted" style={{ marginBottom: 0 }}>Chart library is unavailable.</p>;
    }

    return (
      <div
        className={className || 'shared-line-chart'}
        role="img"
        aria-label={ariaLabel || 'Line chart'}
        style={height ? { height } : undefined}
      >
        <canvas ref={canvasRef} />
      </div>
    );
  }

  function PieChart({ labels, values, colors, options, className, ariaLabel, height }) {
    const canvasRef = React.useRef(null);
    const chartRef = React.useRef(null);
    const chartLibrary = global.Chart;

    React.useEffect(() => {
      if (!canvasRef.current || typeof chartLibrary !== 'function') {
        return undefined;
      }

      if (chartRef.current) {
        chartRef.current.destroy();
        chartRef.current = null;
      }

      const context = canvasRef.current.getContext('2d');
      if (!context) {
        return undefined;
      }

      const normalizedLabels = Array.isArray(labels) ? labels : [];
      const normalizedValues = Array.isArray(values) ? values : [];
      const palette = Array.isArray(colors) && colors.length > 0 ? colors : PIE_CHART_PALETTE;

      chartRef.current = new chartLibrary(context, {
        type: 'pie',
        data: {
          labels: normalizedLabels,
          datasets: [{
            data: normalizedValues,
            backgroundColor: normalizedValues.map((_, index) => palette[index % palette.length]),
            borderColor: '#10212e',
            borderWidth: 1
          }]
        },
        options: Object.assign({
          responsive: true,
          maintainAspectRatio: false,
          animation: false,
          plugins: {
            legend: {
              display: true,
              position: 'right'
            }
          }
        }, options && typeof options === 'object' ? options : {})
      });

      return () => {
        if (chartRef.current) {
          chartRef.current.destroy();
          chartRef.current = null;
        }
      };
    }, [chartLibrary, labels, values, colors, options]);

    if (typeof chartLibrary !== 'function') {
      return <p className="muted" style={{ marginBottom: 0 }}>Chart library is unavailable.</p>;
    }

    return (
      <div
        className={className || 'shared-pie-chart'}
        role="img"
        aria-label={ariaLabel || 'Pie chart'}
        style={height ? { height } : undefined}
      >
        <canvas ref={canvasRef} />
      </div>
    );
  }

  function SegmentedControl({ options, value, onChange, ariaLabel, className }) {
    const items = Array.isArray(options) ? options.filter((option) => option && option.value) : [];
    if (items.length === 0) {
      return null;
    }

    const selectedValue = value == null ? '' : String(value);

    return (
      <div className={`shared-segmented-control ${className || ''}`.trim()} role="group" aria-label={ariaLabel || 'Segmented control'}>
        {items.map((option, index) => {
          const optionValue = String(option.value);
          const isActive = optionValue === selectedValue;
          return (
            <React.Fragment key={optionValue}>
              {index > 0 ? <span className="shared-segmented-divider" aria-hidden="true" /> : null}
              <button
                type="button"
                className={`shared-segmented-option ${isActive ? 'active' : ''}`.trim()}
                aria-pressed={isActive}
                onClick={() => {
                  if (!isActive && typeof onChange === 'function') {
                    onChange(optionValue);
                  }
                }}
              >
                {option.label || optionValue}
              </button>
            </React.Fragment>
          );
        })}
      </div>
    );
  }

  function getCurrencySymbol(currency) {
    if (!currency || typeof currency !== 'string') return '';
    const code = currency.trim().toUpperCase();
    const map = {
      EUR: '€',
      USD: '$',
      GBP: '£',
      JPY: '¥'
    };
    return map[code] || `${code} `;
  }

  global.PortfolioSharedComponents = Object.assign({}, global.PortfolioSharedComponents, {
    BlockingScreenLoader,
    LineChart,
    PieChart,
    SegmentedControl,
    getCurrencySymbol
  });
})(window);
