import { useEffect, useRef, useState } from 'react';

import { createContext } from '@/hooks/useContextSelector';
import { DSPContext, MainModule, dspEngineSingleton } from '@/utils/dsp';

import DelayedLegacyEditButton from './DelayedLegacyEditButton';

/**
 * Creates an FfmpegAudioBuffer from a File object.
 * This is memory-efficient because it only stores compressed file data
 * instead of decoded audio, and decodes on-demand.
 * @param uuid Optional UUID to register the buffer with (e.g., uploadId for uploaded clips)
 */
export const getFfmpegAudioBufferFromFile = async (
  dspModule: MainModule,
  file: File,
  uuid?: string
) => {
  const arrayBuffer = await file.arrayBuffer();
  const uint8Array = new Uint8Array(arrayBuffer);
  return dspModule.FfmpegAudioBuffer.createFromByteArray(uint8Array, uuid);
};

let singletonPromise: Promise<MainModule> | null = null;

let globalModuleAndContext: {
  module: MainModule;
  context: DSPContext;
} | null = null;

export const DSPModuleContext = createContext<{
  module: MainModule;
  context: DSPContext;
}>(undefined as never);

export const DSPModuleContextProvider = ({
  children,
  editModeClipId,
}: {
  children: React.ReactNode;
  editModeClipId?: string;
}) => {
  const [moduleAndContext, setModuleAndContext] = useState<{
    module: MainModule;
    context: DSPContext;
  } | null>(globalModuleAndContext);

  const hasInitialized = useRef(false);

  useEffect(() => {
    if (hasInitialized.current) return;
    hasInitialized.current = true;

    if (globalModuleAndContext) {
      setModuleAndContext(globalModuleAndContext);
    } else {
      if (!singletonPromise) {
        singletonPromise = dspEngineSingleton();
      }

      singletonPromise.then(async (module) => {
        const analytics = new module.AnalyticsObserver();
        const context = await module.DSPContext.create(
          'StudioDSPContext',
          0.9997,
          analytics
        );
        analytics.delete();

        globalModuleAndContext = {
          module,
          context,
        };

        setModuleAndContext(globalModuleAndContext);

        (window as any).dsp = globalModuleAndContext;

        const handleUserInput = () => {
          context.getAudioContext().resume();
          console.log('web audio init ran');
          window.removeEventListener('mousedown', handleUserInput);
        };

        window.addEventListener('mousedown', handleUserInput);
      });
    }
  }, []);

  if (!moduleAndContext) {
    return editModeClipId ? (
      <div className='flex h-full w-full flex-col items-center justify-center'>
        Loading DSP Engine...
        <DelayedLegacyEditButton clipId={editModeClipId} />
      </div>
    ) : null;
  }

  return (
    <DSPModuleContext.Provider value={moduleAndContext}>
      {children}
    </DSPModuleContext.Provider>
  );
};
