import { useState, useEffect } from 'react';
import debounce from 'lodash.debounce';

function mapMeasurementToDisplay(measurement, displaySetService) {
  const { referenceSeriesUID } = measurement;

  const displaySets = displaySetService.getDisplaySetsForSeries(referenceSeriesUID);

  if (!displaySets[0]?.instances) {
    throw new Error('The tracked measurements panel should only be tracking "stack" displaySets.');
  }

  const { findingSites, finding, label: baseLabel, displayText: baseDisplayText } = measurement;

  const firstSite = findingSites?.[0];
  const label = baseLabel || finding?.text || firstSite?.text || '(empty)';

  // Initialize displayText with the structure used in Length.ts and CobbAngle.ts
  const displayText = {
    primary: [],
    secondary: baseDisplayText?.secondary || [],
  };

  // Add baseDisplayText to primary if it exists
  if (baseDisplayText) {
    displayText.primary.push(...baseDisplayText.primary);
  }

  // Add finding sites to primary
  if (findingSites) {
    findingSites.forEach(site => {
      if (site?.text && site.text !== label) {
        displayText.primary.push(site.text);
      }
    });
  }

  // Add finding to primary if it's different from the label
  if (finding && finding.text && finding.text !== label) {
    displayText.primary.push(finding.text);
  }

  return {
    ...measurement,
    displayText,
    label,
  };
}

/**
 * A custom hook that provides mapped measurements based on the given services and filters.
 *
 * @param {Object} servicesManager - The services manager object.
 * @param {Object} options - The options for filtering and mapping measurements.
 * @param {Function} options.measurementFilter - Optional function to filter measurements.
 * @param {Object} options.valueTypes - The value types for mapping measurements.
 * @returns {Array} An array of mapped and filtered measurements.
 */
export function useMeasurements(servicesManager, { measurementFilter }) {
  const { measurementService, displaySetService } = servicesManager.services;
  const [displayMeasurements, setDisplayMeasurements] = useState([]);

  useEffect(() => {
    const updateDisplayMeasurements = () => {
      let measurements = measurementService.getMeasurements();
      if (measurementFilter) {
        measurements = measurements.filter(measurementFilter);
      }
      const mappedMeasurements = measurements.map(m =>
        mapMeasurementToDisplay(m, displaySetService)
      );
      setDisplayMeasurements(prevMeasurements => {
        if (JSON.stringify(prevMeasurements) !== JSON.stringify(mappedMeasurements)) {
          return mappedMeasurements;
        }
        return prevMeasurements;
      });
    };

    const debouncedUpdate = debounce(updateDisplayMeasurements, 100);

    updateDisplayMeasurements();

    const events = [
      measurementService.EVENTS.MEASUREMENT_ADDED,
      measurementService.EVENTS.RAW_MEASUREMENT_ADDED,
      measurementService.EVENTS.MEASUREMENT_UPDATED,
      measurementService.EVENTS.MEASUREMENT_REMOVED,
      measurementService.EVENTS.MEASUREMENTS_CLEARED,
    ];

    const subscriptions = events.map(
      evt => measurementService.subscribe(evt, debouncedUpdate).unsubscribe
    );

    return () => {
      subscriptions.forEach(unsub => unsub());
      debouncedUpdate.cancel();
    };
  }, [measurementService, measurementFilter, displaySetService]);

  return displayMeasurements;
}
