import { useState, useCallback, useEffect, useRef } from 'react';
import { useSelector } from 'react-redux';
import { selectInSession } from '../store/features/activeSessionSlice';
import {
  selectMetronomeSettings,
  selectNoAudioUsers,
  selectClientsWithAudioOverride
} from '../store/features/mixersSlice';
import { throttle } from 'lodash'; // Add lodash for throttling
//import { useJamClient } from '../context/JamClientContext';
import { MIX_MODES } from '../helpers/globals';
import { putTrackSyncChange } from '../helpers/rest';
import useVuHelpers from './useVuHelpers';
import { useJamServerContext } from '../context/JamServerContext';
import { useMixersContext } from '../context/MixersContext';
import { vuStore } from '../stores/vuStore';



/**
 * Custom hook for managing mixer store state and actions.
 * Converted from the original CoffeeScript Reflux store to modern React.
 */
export default function useMixerStore() {
  //const jamClient = useJamClient();
  // Phase 4: Replace CurrentSessionContext with Redux
  const inSession = useSelector(selectInSession);

  // Phase 5: Replace duplicate state with Redux selectors
  const metro = useSelector(selectMetronomeSettings);
  const noAudioUsers = useSelector(selectNoAudioUsers);
  const clientsWithAudioOverride = useSelector(selectClientsWithAudioOverride);

  const {
    jamClient,
  } = useJamServerContext();
  const mixerHelper = useMixersContext();
  const mixerHelperRef = useRef(null);

  const logger = console; // Replace with your logging mechanism if needed
  //const { updateVU } = useVuHelpers();

  // Local state (not duplicated in Redux)
  const [checkingMissingPeers, setCheckingMissingPeers] = useState({});
  const [missingMixerPeers, setMissingMixerPeers] = useState({});
  const [vuMeterUpdatePrefMap, setVuMeterUpdatePrefMap] = useState({ count: 0 });
  const [session, setSession] = useState(null);
  //const [masterMixers, setMasterMixers] = useState(null);
  //const [personalMixers, setPersonalMixers] = useState(null);
  //const [mixers, setMixers] = useState(null); //holds MixerHelper instance

  // Refs for persistent values
  const appRef = useRef(null);
  const gearUtilsRef = useRef(null);
  const sessionUtilsRef = useRef(null);
  const recheckTimeoutRef = useRef(null);

  // Constants
  const METRO_SOUND_LOOKUP = {
    0: "BuiltIn",
    1: "SineWave",
    2: "Beep",
    3: "Click",
    4: "Kick",
    5: "Snare",
    6: "MetroFile"
  };

  // Keep mixerHelperRef in sync with current mixerHelper
  useEffect(() => {
    mixerHelperRef.current = mixerHelper;
  }, [mixerHelper]);

  // Initialize global callbacks
  useEffect(() => {
    if (!window.JK) window.JK = {};
    console.debug("MixerStore: setting up global callbacks", mixerHelper.mixers.current);
    //window.JK.HandleVolumeChangeCallback2 = handleVolumeChangeCallback;
    //window.JK.HandleMetronomeCallback2 = handleMetronomeCallback;
    window.JK.HandleBridgeCallback2 = handleBridgeCallback;
    //window.JK.HandleBackingTrackSelectedCallback2 = handleBackingTrackSelectedCallback;

    return () => {
      // Cleanup
      if (window.JK) {
        //delete window.JK.HandleVolumeChangeCallback2;
        //delete window.JK.HandleMetronomeCallback2;
        delete window.JK.HandleBridgeCallback2;
        //delete window.JK.HandleBackingTrackSelectedCallback2;
      }
      if (recheckTimeoutRef.current) {
        clearTimeout(recheckTimeoutRef.current);
      }
    };
  }, []);

  // Initialize on app ready
  const initialize = useCallback(async (app) => {
    // appRef.current = app;
    // gearUtilsRef.current = window.JK?.GearUtilsInstance;
    // sessionUtilsRef.current = window.JK?.SessionUtils;

    // if (jamClient) {
    //   await jamClient.SetVURefreshRate(150);
    //   await jamClient.RegisterVolChangeCallBack("JK.HandleVolumeChangeCallback2");
    //   await jamClient.setMetronomeOpenCallback("JK.HandleMetronomeCallback2");
    // }
  }, [jamClient]);

  // // Callback handlers
  // const handleVolumeChangeCallback = useCallback((mixerId, isLeft, value, isMuted) => {
  //   // TODO: Visually update mixer
  //   // Original had TODO comments about updating fader values
  //   console.debug("volume change");
  // }, []);

  // const handleMetronomeCallback = useCallback((args) => {
  //   console.debug("MetronomeCallback: ", args);
  //   setMetro(prev => ({
  //     ...prev,
  //     tempo: args.bpm,
  //     cricket: args.cricket,
  //     sound: METRO_SOUND_LOOKUP[args.sound]
  //   }));

  //   // Update mixers with new metro data
  //   setMixers(prevMixers => {
  //     if (!prevMixers) return null;
  //     return new window.MixerHelper(session, masterMixers, personalMixers, metro, noAudioUsers, clientsWithAudioOverride, prevMixers.mixMode || MIX_MODES.PERSONAL);
  //   });

  //   issueChange();
  // }, [session, masterMixers, personalMixers, noAudioUsers, clientsWithAudioOverride, issueChange]);


  const handleBridgeCallback = useCallback((vuData) => {
    let eventName = null;
    let mixerId = null;
    const value = null;
    let vuInfo = null;

    // const vuMeterUpdateRate = localStorage.getItem('vuMeterUpdateRate') || 'fast';
    // this.vuMeterUpdatePrefMap['count'] = (this.vuMeterUpdatePrefMap['count'] || 0) + 1;

    // if ((vuMeterUpdateRate === 'medium') && ((this.vuMeterUpdatePrefMap['count'] % 3) !== 0)) {
    //   // skip this update
    //   return;
    // }
    // if ((vuMeterUpdateRate === 'slow') && ((this.vuMeterUpdatePrefMap['count'] % 9) !== 0)) {
    //   // skip this update
    //   return;
    // }
    //console.log('vuMeterUpdateRate', vuMeterUpdateRate, @vuMeterUpdatePrefMap['count'])
    //this.vuMeterUpdatePrefMap['count'] = 0;

    //console.log("_DEBUG_ XXX: ", vuData);


    //const result = [];
    for (vuInfo of vuData) {
      eventName = vuInfo[0];
      const vuVal = 0.0;
      if (eventName === "vu") {
        mixerId = vuInfo[1];
        const mode = vuInfo[2];
        const leftValue = vuInfo[3];
        const leftClipping = vuInfo[4];
        const rightValue = vuInfo[5];
        const rightClipping = vuInfo[6];
        // TODO - no guarantee range will be -80 to 20. Get from the
        // GetControlState for this mixer which returns min/max
        // value is a DB value from -80 to 20. Convert to float from 0.0-1.0

        // Convert dB to 0.0-1.0 range (existing logic)
        const normalizedLevel = (leftValue + 80) / 80;

        // Create qualified ID matching existing pattern
        const fqId = (mode ? 'M' : 'P') + mixerId;

        // Route to external store instead of mixerHelper
        vuStore.updateLevel(fqId, normalizedLevel, leftClipping);
      }
    }


  }, []);



  // const handleBackingTrackSelectedCallback = useCallback(() => {
  //   console.debug("backing track selected");
  // }, []);

  // Session management
  const sessionEnded = useCallback(() => {
    // Phase 5: Local state only - Redux handles noAudioUsers cleanup
    setCheckingMissingPeers({});
    setMissingMixerPeers({});
    if (recheckTimeoutRef.current) {
      clearTimeout(recheckTimeoutRef.current);
      recheckTimeoutRef.current = null;
    }
  }, []);

  const onSessionChange = useCallback(async (newSession) => {
    console.log("[MixerStore] onSessionChange START:", {
      sessionId: newSession.id(),
      timestamp: Date.now()
    });
    console.debug("MixerStore: onSessionChange", newSession);

    if (!newSession) return;

    if (!inSession) {
      sessionEnded();
    }

    setSession(newSession);

    if (jamClient) {
      console.log("[MixerStore] Fetching mixer control state...");
      const newMasterMixers = await jamClient.SessionGetAllControlState(true);
      const newPersonalMixers = await jamClient.SessionGetAllControlState(false);

      console.log("[MixerStore] Fetched mixers:", {
        masterCount: newMasterMixers.length,
        personalCount: newPersonalMixers.length
      });

      // Initialize the mixerHelper with the constructor parameters
      console.debug("MixerStore: onSessionChange: initializing mixerHelper", { newSession, newMasterMixers, newPersonalMixers, metro, noAudioUsers, clientsWithAudioOverride });

      mixerHelper.updateMixerData(newSession, newMasterMixers, newPersonalMixers, metro, noAudioUsers, clientsWithAudioOverride, MIX_MODES.PERSONAL);

      // const m = useMixerHelper(newSession, newMasterMixers, newPersonalMixers, metro, noAudioUsers, clientsWithAudioOverride, mixers?.mixMode || MIX_MODES.PERSONAL);
      // console.debug("MixerStore: onSessionChange: ", m);
      // setMixers(m);
    }
    console.log("[MixerStore] onSessionChange END");
  }, [jamClient, mixerHelper, metro, noAudioUsers, clientsWithAudioOverride, inSession, sessionEnded]);

  // // Mixer actions
  // const onMute = useCallback(async (mixersToMute, muting) => {
  //   const mixersArray = Array.isArray(mixersToMute) ? mixersToMute : [mixersToMute];

  //   for (const mixer of mixersArray) {
  //     if (mixers) {
  //       await mixers.mute(mixer.id, mixer.mode, muting);
  //     }
  //   }

  //   issueChange();
  // }, [mixers, issueChange]);

  // const onFaderChanged = useCallback(async (data, mixersList, gainType, controlGroup) => {
  //   if (mixers) {
  //     await mixers.faderChanged(data, mixersList, gainType, controlGroup);
  //   }
  //   issueChange();
  // }, [mixers, issueChange]);

  // const onPanChanged = useCallback((data, mixersList, groupId) => {
  //   if (mixers) {
  //     mixers.panChanged(data, mixersList, groupId);
  //   }
  //   issueChange();
  // }, [mixers, issueChange]);

  // const onLoopChanged = useCallback(async (mixer, shouldLoop) => {
  //   if (mixers) {
  //     await mixers.loopChanged(mixer, shouldLoop);
  //   }
  // }, [mixers]);

  // const onOpenMetronome = useCallback(async () => {
  //   if (jamClient && mixers) {
  //     await jamClient.SessionStopPlay();
  //     await jamClient.SessionOpenMetronome(mixers.metro.tempo, mixers.metro.sound, 1, 0);
  //   }
  // }, [jamClient, mixers]);

  // const onMetronomeChanged = useCallback(async (tempo, sound) => {
  //   console.debug("onMetronomeChanged", tempo, sound);

  //   setMetro(prev => ({ ...prev, tempo, sound }));

  //   if (jamClient) {
  //     await jamClient.SessionSetMetronome(tempo, sound, 1, 0);
  //   }

  //   setMixers(prevMixers => {
  //     if (!prevMixers) return null;
  //     return new window.MixerHelper(session, masterMixers, personalMixers, { ...metro, tempo, sound }, noAudioUsers, clientsWithAudioOverride, prevMixers.mixMode || MIX_MODES.PERSONAL);
  //   });

  //   issueChange();
  // }, [jamClient, session, masterMixers, personalMixers, noAudioUsers, clientsWithAudioOverride, issueChange]);

  // // Media close handlers
  // const onCloseMedia = useCallback((codeInitiated) => {
  //   console.debug("MixerStore: onCloseMedia", codeInitiated);
  //   if (session?.recordedTracks()) {
  //     closeRecording(codeInitiated);
  //   } else if (session?.jamTracks() || session?.downloadingJamTrack) {
  //     closeJamTrack(codeInitiated);
  //   } else if (session?.backingTrack()?.path) {
  //     closeBackingTrack(codeInitiated);
  //   } else if (session?.isMetronomeOpen()) {
  //     closeMetronomeTrack(codeInitiated);
  //   } else {
  //     console.error("don't know how to close open media", session);
  //   }
  // }, [session]);

  // const closeRecording = useCallback((codeInitiated) => {
  //   console.debug("closing recording");

  //   if (!mixers?.mediaSummary.isOpener) {
  //     console.debug("not recording as not opener");
  //     return;
  //   }

  //   // TODO: Implement SessionActions.closeMedia
  //   // SessionActions.closeMedia(codeInitiated);
  // }, [mixers]);

  // const closeMetronomeTrack = useCallback((codeInitiated) => {
  //   console.debug("closing metronome");

  //   // TODO: Implement SessionActions.closeMedia
  //   // SessionActions.closeMedia(codeInitiated);
  // }, []);

  // const closeBackingTrack = useCallback((codeInitiated) => {
  //   console.debug("closing backing track");

  //   if (!mixers?.mediaSummary.isOpener) {
  //     console.debug("not closing backing as not opener");
  //     return;
  //   }

  //   // TODO: Implement SessionActions.closeMedia
  //   // SessionActions.closeMedia(codeInitiated);
  // }, [mixers]);

  // const closeJamTrack = useCallback((codeInitiated) => {
  //   console.debug("closing jam track");

  //   if (!mixers?.mediaSummary.isOpener) {
  //     console.debug("not closing jamtrack as not opener");
  //     return;
  //   }

  //   // TODO: Implement SessionActions.closeMedia
  //   // SessionActions.closeMedia(codeInitiated);
  // }, [mixers]);

  // // Peer management
  // const onDeadUserRemove = useCallback((clientId) => {
  //   if (!session?.inSession()) return;

  //   const participant = session.participantsEverSeen?.[clientId];
  //   if (participant) {
  //     console.debug("todo: notify dead user");
  //     // TODO: trigger some notification store
  //   }

  //   setNoAudioUsers(prev => ({ ...prev, [clientId]: true }));
  //   issueChange();
  // }, [session, issueChange]);

  // const onClientsWithAudio = useCallback((clients) => {
  //   setClientsWithAudioOverride(clients);
  // }, []);

  // const onMissingPeerMixer = useCallback((clientId) => {
  //   const missingPeerAttempts = missingMixerPeers[clientId];

  //   if (!missingPeerAttempts || missingPeerAttempts < 5) {
  //     setCheckingMissingPeers(prev => ({ ...prev, [clientId]: true }));
  //     if (!recheckTimeoutRef.current) {
  //       recheckTimeoutRef.current = setTimeout(recheckForMixers, 2000);
  //     }
  //   } else {
  //     console.debug("ignoring missing peer recheck. missingPeerAttempts:", missingPeerAttempts);
  //   }
  // }, [missingMixerPeers]);

  // const recheckForMixers = useCallback(async () => {
  //   setCheckingMissingPeers(prev => {
  //     const newChecking = { ...prev };
  //     for (const clientId in newChecking) {
  //       setMissingMixerPeers(prevMissing => {
  //         const attempts = (prevMissing[clientId] || 0) + 1;
  //         return { ...prevMissing, [clientId]: attempts };
  //       });
  //     }
  //     return {};
  //   });

  //   recheckTimeoutRef.current = null;

  //   if (jamClient) {
  //     const newMasterMixers = await jamClient.SessionGetAllControlState(true);
  //     const newPersonalMixers = await jamClient.SessionGetAllControlState(false);

  //     setMasterMixers(newMasterMixers);
  //     setPersonalMixers(newPersonalMixers);

  //     console.debug("MixerStore: recheckForMixers");
  //     setMixers(prevMixers => {
  //       if (!prevMixers) return null;
  //       return new window.MixerHelper(session, newMasterMixers, newPersonalMixers, metro, noAudioUsers, clientsWithAudioOverride, prevMixers.mixMode || MIX_MODES.PERSONAL);
  //     });
  //   }

  //   issueChange();
  // }, [jamClient, session, metro, noAudioUsers, clientsWithAudioOverride, issueChange]);

  // // Other handlers
  // const onInitGain = useCallback((mixer) => {
  //   if (mixers) {
  //     mixers.initGain(mixer);
  //   }
  // }, [mixers]);

  // const onInitPan = useCallback((mixer) => {
  //   if (mixers) {
  //     mixers.initPan(mixer);
  //   }
  // }, [mixers]);

  // const onMixersChanged = useCallback(async (type, text) => {
  //   if (jamClient) {
  //     const newMasterMixers = await jamClient.SessionGetAllControlState(true);
  //     const newPersonalMixers = await jamClient.SessionGetAllControlState(false);

  //     setMasterMixers(newMasterMixers);
  //     setPersonalMixers(newPersonalMixers);

  //     console.debug("MixerStore: onMixersChanged");

  //     setMixers(prevMixers => {
  //       if (!prevMixers) return null;
  //       return new window.MixerHelper(session, newMasterMixers, newPersonalMixers, metro, noAudioUsers, clientsWithAudioOverride, prevMixers.mixMode || MIX_MODES.PERSONAL);
  //     });

  //     // TODO: Implement SessionActions.mixersChanged.trigger
  //     // SessionActions.mixersChanged.trigger(type, text, mixers.getTrackInfo());
  //   }

  //   issueChange();
  // }, [jamClient, session, metro, noAudioUsers, clientsWithAudioOverride, issueChange]);

  // const onMixerModeChanged = useCallback((mode) => {
  //   if (mode === MIX_MODES.MASTER && appRef.current?.layout) {
  //     appRef.current.layout.showDialog('session-master-mix-dialog');
  //   } else if (appRef.current?.layout) {
  //     appRef.current.layout.closeDialog('session-master-mix-dialog');
  //   }
  // }, []);

  // const onSyncTracks = useCallback(async () => {
  //   console.debug("MixerStore: onSyncTracks");
  //   if (!session?.inSession()) {
  //     console.debug("dropping sync tracks because no longer in session");
  //     return;
  //   }

  //   if (mixers) {
  //     const allTracks = await mixers.getTrackInfo();
  //     console.log('allTracks', allTracks);
  //     const inputTracks = allTracks.userTracks;
  //     const backingTracks = allTracks.backingTracks;
  //     const metronomeTracks = allTracks.metronomeTracks;

  //     // create a trackSync request based on backend data
  //     const syncTrackRequest = {
  //       client_id: appRef.current?.clientId,
  //       tracks: inputTracks,
  //       backing_tracks: backingTracks,
  //       metronome_open: metronomeTracks.length > 0,
  //       id: session.id()
  //     };

  //     try {
  //       await putTrackSyncChange(syncTrackRequest);
  //     } catch (error) {
  //       if (error.status !== 404) {
  //         appRef.current?.notify({
  //           "title": "Can't Sync Local Tracks",
  //           "text": "The client is unable to sync local track information with the server.  You should rejoin the session to ensure a good experience.",
  //           "icon_url": "/assets/content/icon_alert_big.png"
  //         });
  //       } else {
  //         console.debug("Unable to sync local tracks because session is gone.");
  //       }
  //     }
  //   }
  // }, [session, mixers]);

  // Return the state and handlers
  return {
    // State
    // session,
    // metro,
    // noAudioUsers,
    // clientsWithAudioOverride,

    // Initialization
    initialize,

    // Handlers
    onSessionChange,
    // onMute,
    // onFaderChanged,
    // onPanChanged,
    // onLoopChanged,
    // onOpenMetronome,
    // onMetronomeChanged,
    // onCloseMedia,
    // onDeadUserRemove,
    // onClientsWithAudio,
    // onMissingPeerMixer,
    // onInitGain,
    // onInitPan,
    // onMixersChanged,
    // onMixerModeChanged,
    // onSyncTracks,

    // // Callbacks
    // handleVolumeChangeCallback,
    // handleMetronomeCallback,
    // handleBridgeCallback,
    // handleBackingTrackSelectedCallback,
  };
}
