import {useCallback, useEffect} from 'react';
import {
  SharedValue,
  useFrameCallback,
  useSharedValue,
} from 'react-native-reanimated';
import {WAVEFORM_BARS_COUNT} from '@components/_custom/Audio/WaveForms/constants';
import {useUnmount} from '@hooks/useUnmount';

const SILENCE_THRESHOLD = 0.15;
const SHIFT_INTERVAL_MS = 50;
/** How many waveform bars are produced per second of recording (1000 / SHIFT_INTERVAL_MS). */
export const BARS_PER_SECOND = 1000 / SHIFT_INTERVAL_MS;

const normalize = (value: number) => {
  'worklet';
  return Math.max(0, (value - SILENCE_THRESHOLD) / (1 - SILENCE_THRESHOLD));
};

/** Downsample `raw` into `targetCount` bars using max-pooling. */
const downsampleBars = (raw: number[], targetCount: number): number[] => {
  'worklet';
  const n = raw.length;
  const result: number[] = [];
  for (let i = 0; i < targetCount; i++) {
    const start = (i / targetCount) * n;
    const end = ((i + 1) / targetCount) * n;
    let max = 0;
    for (let j = Math.floor(start); j < Math.ceil(end) && j < n; j++) {
      if (raw[j] > max) {
        max = raw[j];
      }
    }
    result.push(max);
  }
  return result;
};

export const useWaveformBarHeights = ({
  meteringLevel,
  isActive = true,
  barsCount = WAVEFORM_BARS_COUNT,
}: {
  meteringLevel: SharedValue<number>;
  isActive?: boolean;
  barsCount?: number;
}) => {
  /**
   * Live scrolling window — always the last `barsCount` raw samples.
   * Used during active recording to show a real-time "ticker tape" waveform.
   */
  const liveBarHeights = useSharedValue<number[]>(Array(barsCount).fill(0));

  /**
   * Compressed summary of the entire recording — always `barsCount` bars.
   * Right-aligned if n < barsCount, max-pooled if n ≥ barsCount.
   */
  const compressedBarHeights = useSharedValue<number[]>(
    Array(barsCount).fill(0),
  );

  /**
   * Every raw sample captured during recording.
   * At 20 samples/sec a 10-min recording produces ~12 000 entries (≈ 96 KB).
   */
  const rawBars = useSharedValue<number[]>([]);

  const lastShiftMs = useSharedValue(0);

  const frameCb = useFrameCallback(info => {
    if (
      barsCount === 0 ||
      info.timestamp - lastShiftMs.value < SHIFT_INTERVAL_MS
    ) {
      return;
    }
    lastShiftMs.value = info.timestamp;

    const newHeight = normalize(meteringLevel.value);

    // ── Live view: rolling window of the last barsCount samples ──────────────
    liveBarHeights.value = [...liveBarHeights.value.slice(1), newHeight];

    // ── Compressed view: full recording aggregated into barsCount bars ────────
    const newRaw = [...rawBars.value, newHeight];
    rawBars.value = newRaw;

    const n = newRaw.length;
    if (n < barsCount) {
      // Right-align captured bars; silence fills the left side.
      const result = Array(barsCount).fill(0);
      for (let i = 0; i < n; i++) {
        result[barsCount - n + i] = newRaw[i];
      }
      compressedBarHeights.value = result;
    } else {
      // Zoom out: compress the entire history into exactly barsCount bars.
      compressedBarHeights.value = downsampleBars(newRaw, barsCount);
    }
  });

  const reset = useCallback(() => {
    liveBarHeights.value = Array(barsCount).fill(0);
    compressedBarHeights.value = Array(barsCount).fill(0);
    rawBars.value = [];
  }, [liveBarHeights, compressedBarHeights, rawBars, barsCount]);

  useEffect(() => {
    frameCb.setActive(isActive);
  }, [isActive, frameCb]);

  useUnmount(() => {
    frameCb.setActive(false);
  });

  return {
    /** Real-time scrolling bars — use during active recording. */
    liveBarHeights,
    /** Full-recording summary bars — snapshot `.value` for the paused player. */
    compressedBarHeights,
    reset,
  };
};
