import { createContext, useContext, useState, useEffect, useRef, useCallback, ReactNode } from 'react';

type SoundType = 'click' | 'beep' | 'hover' | 'boot' | 'success' | 'error';

interface SettingsContextType {
  crtEnabled: boolean;
  setCrtEnabled: (enabled: boolean) => void;
  soundEnabled: boolean;
  setSoundEnabled: (enabled: boolean) => void;
  cryptoConsent: boolean;
  setCryptoConsent: (consent: boolean) => void;
  playSound: (type: SoundType) => void;
  hashrate: number;
  setHashrate: (rate: number) => void;
  totalHashes: number;
  setTotalHashes: (hashes: number) => void;
  acceptedHashes: number;
  setAcceptedHashes: (hashes: number) => void;
}

const SettingsContext = createContext<SettingsContextType | undefined>(undefined);

export const SettingsProvider = ({ children }: { children: ReactNode }) => {
  const [crtEnabled, setCrtEnabled] = useState(() => {
    const saved = localStorage.getItem('crtEnabled');
    return saved !== null ? JSON.parse(saved) : true;
  });
  
  const [soundEnabled, setSoundEnabled] = useState(() => {
    const saved = localStorage.getItem('soundEnabled');
    return saved !== null ? JSON.parse(saved) : true;
  });
  
  const [cryptoConsent, setCryptoConsent] = useState(() => {
    const saved = localStorage.getItem('cryptoConsent');
    return saved !== null ? JSON.parse(saved) : false;
  });

  const [hashrate, setHashrate] = useState(0);
  const [totalHashes, setTotalHashes] = useState(0);
  const [acceptedHashes, setAcceptedHashes] = useState(0);

  // Single AudioContext instance, persisted across renders
  const audioContextRef = useRef<AudioContext | null>(null);
  
  // Use ref to always have current soundEnabled value in callbacks
  const soundEnabledRef = useRef(soundEnabled);
  useEffect(() => {
    soundEnabledRef.current = soundEnabled;
  }, [soundEnabled]);

  // Get or create AudioContext
  const getAudioContext = useCallback(() => {
    if (!audioContextRef.current) {
      audioContextRef.current = new (window.AudioContext || (window as any).webkitAudioContext)();
    }
    
    // Resume if suspended (browser autoplay policy)
    if (audioContextRef.current.state === 'suspended') {
      audioContextRef.current.resume();
    }
    
    return audioContextRef.current;
  }, []);

  // Cleanup on unmount
  useEffect(() => {
    return () => {
      if (audioContextRef.current) {
        audioContextRef.current.close();
        audioContextRef.current = null;
      }
    };
  }, []);

  useEffect(() => {
    localStorage.setItem('crtEnabled', JSON.stringify(crtEnabled));
  }, [crtEnabled]);

  useEffect(() => {
    localStorage.setItem('soundEnabled', JSON.stringify(soundEnabled));
  }, [soundEnabled]);

  useEffect(() => {
    localStorage.setItem('cryptoConsent', JSON.stringify(cryptoConsent));
  }, [cryptoConsent]);

  const playSound = useCallback((type: SoundType) => {
    // Use ref to ensure we always have the latest value
    if (!soundEnabledRef.current) return;
    
    try {
      const audioContext = getAudioContext();
      const oscillator = audioContext.createOscillator();
      const gainNode = audioContext.createGain();
      
      oscillator.connect(gainNode);
      gainNode.connect(audioContext.destination);
      
      const now = audioContext.currentTime;
      
      switch (type) {
        case 'click':
          oscillator.frequency.value = 800;
          gainNode.gain.value = 0.1;
          oscillator.start(now);
          oscillator.stop(now + 0.05);
          break;
        case 'beep':
          oscillator.frequency.value = 1200;
          gainNode.gain.value = 0.08;
          oscillator.start(now);
          oscillator.stop(now + 0.1);
          break;
        case 'hover':
          oscillator.frequency.value = 600;
          gainNode.gain.value = 0.05;
          oscillator.start(now);
          oscillator.stop(now + 0.03);
          break;
        case 'boot':
          oscillator.type = 'sawtooth';
          oscillator.frequency.setValueAtTime(200, now);
          oscillator.frequency.exponentialRampToValueAtTime(800, now + 0.2);
          gainNode.gain.setValueAtTime(0.1, now);
          gainNode.gain.exponentialRampToValueAtTime(0.01, now + 0.3);
          oscillator.start(now);
          oscillator.stop(now + 0.3);
          break;
        case 'success':
          oscillator.frequency.setValueAtTime(800, now);
          oscillator.frequency.setValueAtTime(1200, now + 0.1);
          gainNode.gain.value = 0.1;
          oscillator.start(now);
          oscillator.stop(now + 0.2);
          break;
        case 'error':
          oscillator.type = 'square';
          oscillator.frequency.value = 150;
          gainNode.gain.value = 0.08;
          oscillator.start(now);
          oscillator.stop(now + 0.15);
          break;
      }
    } catch (e) {
      // Silently fail if audio context has issues
      console.warn('Audio playback failed:', e);
    }
  }, [getAudioContext]);

  return (
    <SettingsContext.Provider
      value={{
        crtEnabled,
        setCrtEnabled,
        soundEnabled,
        setSoundEnabled,
        cryptoConsent,
        setCryptoConsent,
        playSound,
        hashrate,
        setHashrate,
        totalHashes,
        setTotalHashes,
        acceptedHashes,
        setAcceptedHashes,
      }}
    >
      {children}
    </SettingsContext.Provider>
  );
};

export const useSettings = () => {
  const context = useContext(SettingsContext);
  if (context === undefined) {
    throw new Error('useSettings must be used within a SettingsProvider');
  }
  return context;
};
