import sessionUIReducer, {
  openModal,
  closeModal,
  toggleModal,
  closeAllModals,
  openPanel,
  closePanel,
  togglePanel,
  setParticipantLayout,
  toggleParticipantVideos,
  setShowMixer,
  toggleMixer,
  // Phase 5: Media UI actions
  setShowMyMixes,
  toggleMyMixes,
  setShowCustomMixes,
  toggleCustomMixes,
  setEditingMixdownId,
  setCreatingMixdown,
  setCreateMixdownErrors,
  // Phase 5: Mixer UI actions
  setMixMode,
  toggleMixMode,
  setCurrentMixerRange,
  // Recording actions
  setRecordingStarted,
  setRecordingStopped,
  resetUI,
  selectModal,
  selectAllModals,
  selectIsAnyModalOpen,
  selectPanel,
  selectParticipantLayout,
  selectShowMixer,
  // Phase 5: Media UI selectors
  selectShowMyMixes,
  selectShowCustomMixes,
  selectEditingMixdownId,
  selectCreatingMixdown,
  selectCreateMixdownErrors,
  selectMediaUI,
  // Phase 5: Mixer UI selectors
  selectMixMode,
  selectCurrentMixerRange,
  selectMixerUI,
  // Recording selectors
  selectIsRecording,
  selectRecordingId,
  selectThisClientStartedRecording
} from '../sessionUISlice';

describe('sessionUISlice', () => {
  const initialState = {
    modals: {
      settings: false,
      invite: false,
      volume: false,
      recording: false,
      leave: false,
      jamTrack: false,
      backingTrack: false,
      mediaControls: false,
      metronome: false,
      videoSettings: false
    },
    panels: {
      chat: true,
      mixer: false,
      participants: true,
      tracks: true
    },
    view: {
      participantLayout: 'grid',
      showParticipantVideos: true,
      showMixer: false,
      sidebarCollapsed: false
    },
    // Phase 5: Media UI state
    mediaUI: {
      showMyMixes: false,
      showCustomMixes: false,
      editingMixdownId: null,
      creatingMixdown: false,
      createMixdownErrors: null
    },
    // Phase 5: Mixer UI state
    mixerUI: {
      mixMode: 'PERSONAL',
      currentMixerRange: {
        min: null,
        max: null
      }
    },
    // JamTrack UI state
    openJamTrack: null,
    jamTrackUI: {
      lastUsedMixdownId: null,
      volume: 100
    },
    // Recording state
    recording: {
      isRecording: false,
      recordingId: null,
      thisClientStartedRecording: false
    }
  };

  describe('reducer', () => {
    it('should return the initial state', () => {
      expect(sessionUIReducer(undefined, { type: 'unknown' })).toEqual(initialState);
    });
  });

  describe('modal actions', () => {
    it('should handle openModal', () => {
      const actual = sessionUIReducer(initialState, openModal('settings'));
      expect(actual.modals.settings).toBe(true);
    });

    it('should handle closeModal', () => {
      const stateWithOpenModal = {
        ...initialState,
        modals: { ...initialState.modals, settings: true }
      };
      const actual = sessionUIReducer(stateWithOpenModal, closeModal('settings'));
      expect(actual.modals.settings).toBe(false);
    });

    it('should handle toggleModal', () => {
      // Toggle from false to true
      const actual1 = sessionUIReducer(initialState, toggleModal('settings'));
      expect(actual1.modals.settings).toBe(true);

      // Toggle from true to false
      const actual2 = sessionUIReducer(actual1, toggleModal('settings'));
      expect(actual2.modals.settings).toBe(false);
    });

    it('should handle closeAllModals', () => {
      const stateWithOpenModals = {
        ...initialState,
        modals: {
          settings: true,
          invite: true,
          volume: true,
          recording: false,
          leave: true,
          jamTrack: false,
          backingTrack: true,
          mediaControls: false,
          metronome: false,
          videoSettings: false
        }
      };
      const actual = sessionUIReducer(stateWithOpenModals, closeAllModals());

      // All modals should be closed
      Object.values(actual.modals).forEach(modalState => {
        expect(modalState).toBe(false);
      });
    });

    it('should open multiple modals independently', () => {
      let state = sessionUIReducer(initialState, openModal('settings'));
      state = sessionUIReducer(state, openModal('invite'));
      state = sessionUIReducer(state, openModal('volume'));

      expect(state.modals.settings).toBe(true);
      expect(state.modals.invite).toBe(true);
      expect(state.modals.volume).toBe(true);
      expect(state.modals.recording).toBe(false);
    });
  });

  describe('panel actions', () => {
    it('should handle openPanel', () => {
      const stateWithClosedPanel = {
        ...initialState,
        panels: { ...initialState.panels, mixer: false }
      };
      const actual = sessionUIReducer(stateWithClosedPanel, openPanel('mixer'));
      expect(actual.panels.mixer).toBe(true);
    });

    it('should handle closePanel', () => {
      const actual = sessionUIReducer(initialState, closePanel('chat'));
      expect(actual.panels.chat).toBe(false);
    });

    it('should handle togglePanel', () => {
      // Toggle from true to false
      const actual1 = sessionUIReducer(initialState, togglePanel('chat'));
      expect(actual1.panels.chat).toBe(false);

      // Toggle from false to true
      const actual2 = sessionUIReducer(actual1, togglePanel('chat'));
      expect(actual2.panels.chat).toBe(true);
    });
  });

  describe('view preference actions', () => {
    it('should handle setParticipantLayout', () => {
      const actual = sessionUIReducer(initialState, setParticipantLayout('list'));
      expect(actual.view.participantLayout).toBe('list');
    });

    it('should handle toggleParticipantVideos', () => {
      const actual1 = sessionUIReducer(initialState, toggleParticipantVideos());
      expect(actual1.view.showParticipantVideos).toBe(false);

      const actual2 = sessionUIReducer(actual1, toggleParticipantVideos());
      expect(actual2.view.showParticipantVideos).toBe(true);
    });

    it('should handle setShowMixer', () => {
      const actual = sessionUIReducer(initialState, setShowMixer(true));
      expect(actual.view.showMixer).toBe(true);
    });

    it('should handle toggleMixer', () => {
      const actual1 = sessionUIReducer(initialState, toggleMixer());
      expect(actual1.view.showMixer).toBe(true);

      const actual2 = sessionUIReducer(actual1, toggleMixer());
      expect(actual2.view.showMixer).toBe(false);
    });
  });

  describe('resetUI', () => {
    it('should reset all UI state to initial', () => {
      const modifiedState = {
        modals: {
          settings: true,
          invite: true,
          volume: false,
          recording: true,
          leave: false,
          jamTrack: true,
          backingTrack: false,
          mediaControls: true,
          metronome: false,
          videoSettings: false
        },
        panels: {
          chat: false,
          mixer: true,
          participants: false,
          tracks: false
        },
        view: {
          participantLayout: 'compact',
          showParticipantVideos: false,
          showMixer: true,
          sidebarCollapsed: true
        }
      };

      const actual = sessionUIReducer(modifiedState, resetUI());
      expect(actual).toEqual(initialState);
    });
  });

  describe('selectors', () => {
    const mockState = {
      sessionUI: {
        modals: {
          settings: true,
          invite: false,
          volume: true,
          recording: false,
          leave: false,
          jamTrack: false,
          backingTrack: false,
          mediaControls: false,
          metronome: false,
          videoSettings: false
        },
        panels: {
          chat: true,
          mixer: false,
          participants: true,
          tracks: false
        },
        view: {
          participantLayout: 'list',
          showParticipantVideos: false,
          showMixer: true,
          sidebarCollapsed: false
        }
      }
    };

    it('selectModal should return correct modal state', () => {
      expect(selectModal('settings')(mockState)).toBe(true);
      expect(selectModal('invite')(mockState)).toBe(false);
      expect(selectModal('volume')(mockState)).toBe(true);
    });

    it('selectAllModals should return all modals', () => {
      expect(selectAllModals(mockState)).toEqual(mockState.sessionUI.modals);
    });

    it('selectIsAnyModalOpen should return true when any modal is open', () => {
      expect(selectIsAnyModalOpen(mockState)).toBe(true);
    });

    it('selectIsAnyModalOpen should return false when no modals are open', () => {
      const stateWithNoModals = {
        sessionUI: {
          ...mockState.sessionUI,
          modals: {
            settings: false,
            invite: false,
            volume: false,
            recording: false,
            leave: false,
            jamTrack: false,
            backingTrack: false,
            mediaControls: false,
            metronome: false,
            videoSettings: false
          }
        }
      };
      expect(selectIsAnyModalOpen(stateWithNoModals)).toBe(false);
    });

    it('selectPanel should return correct panel state', () => {
      expect(selectPanel('chat')(mockState)).toBe(true);
      expect(selectPanel('mixer')(mockState)).toBe(false);
      expect(selectPanel('tracks')(mockState)).toBe(false);
    });

    it('selectParticipantLayout should return correct layout', () => {
      expect(selectParticipantLayout(mockState)).toBe('list');
    });

    it('selectShowMixer should return correct mixer visibility', () => {
      expect(selectShowMixer(mockState)).toBe(true);
    });
  });

  // Phase 5: Media UI tests
  describe('media UI actions', () => {
    it('should handle setShowMyMixes', () => {
      const actual = sessionUIReducer(initialState, setShowMyMixes(true));
      expect(actual.mediaUI.showMyMixes).toBe(true);
    });

    it('should handle toggleMyMixes', () => {
      const actual1 = sessionUIReducer(initialState, toggleMyMixes());
      expect(actual1.mediaUI.showMyMixes).toBe(true);

      const actual2 = sessionUIReducer(actual1, toggleMyMixes());
      expect(actual2.mediaUI.showMyMixes).toBe(false);
    });

    it('should handle setShowCustomMixes', () => {
      const actual = sessionUIReducer(initialState, setShowCustomMixes(true));
      expect(actual.mediaUI.showCustomMixes).toBe(true);
    });

    it('should handle toggleCustomMixes', () => {
      const actual1 = sessionUIReducer(initialState, toggleCustomMixes());
      expect(actual1.mediaUI.showCustomMixes).toBe(true);

      const actual2 = sessionUIReducer(actual1, toggleCustomMixes());
      expect(actual2.mediaUI.showCustomMixes).toBe(false);
    });

    it('should handle setEditingMixdownId', () => {
      const actual = sessionUIReducer(initialState, setEditingMixdownId('mixdown-123'));
      expect(actual.mediaUI.editingMixdownId).toBe('mixdown-123');
    });

    it('should handle setCreatingMixdown', () => {
      const actual = sessionUIReducer(initialState, setCreatingMixdown(true));
      expect(actual.mediaUI.creatingMixdown).toBe(true);
    });

    it('should handle setCreateMixdownErrors', () => {
      const errors = { name: 'Name is required' };
      const actual = sessionUIReducer(initialState, setCreateMixdownErrors(errors));
      expect(actual.mediaUI.createMixdownErrors).toEqual(errors);
    });

    it('should clear mixdown errors with null', () => {
      const stateWithErrors = {
        ...initialState,
        mediaUI: { ...initialState.mediaUI, createMixdownErrors: { name: 'Error' } }
      };

      const actual = sessionUIReducer(stateWithErrors, setCreateMixdownErrors(null));
      expect(actual.mediaUI.createMixdownErrors).toBeNull();
    });
  });

  // Phase 5: Mixer UI tests
  describe('mixer UI actions', () => {
    it('should handle setMixMode', () => {
      const actual = sessionUIReducer(initialState, setMixMode('MASTER'));
      expect(actual.mixerUI.mixMode).toBe('MASTER');
    });

    it('should handle toggleMixMode from PERSONAL to MASTER', () => {
      const actual = sessionUIReducer(initialState, toggleMixMode());
      expect(actual.mixerUI.mixMode).toBe('MASTER');
    });

    it('should handle toggleMixMode from MASTER to PERSONAL', () => {
      const stateWithMaster = {
        ...initialState,
        mixerUI: { ...initialState.mixerUI, mixMode: 'MASTER' }
      };

      const actual = sessionUIReducer(stateWithMaster, toggleMixMode());
      expect(actual.mixerUI.mixMode).toBe('PERSONAL');
    });

    it('should handle setCurrentMixerRange', () => {
      const range = { min: 0, max: 100 };
      const actual = sessionUIReducer(initialState, setCurrentMixerRange(range));
      expect(actual.mixerUI.currentMixerRange).toEqual(range);
    });

    it('should handle partial mixer range update', () => {
      const stateWithRange = {
        ...initialState,
        mixerUI: { ...initialState.mixerUI, currentMixerRange: { min: 10, max: 90 } }
      };

      const actual = sessionUIReducer(stateWithRange, setCurrentMixerRange({ min: 10, max: 90 }));
      expect(actual.mixerUI.currentMixerRange.min).toBe(10);
      expect(actual.mixerUI.currentMixerRange.max).toBe(90);
    });
  });

  // Phase 5: Extended resetUI test
  describe('resetUI with Phase 5 state', () => {
    it('should reset media UI and mixer UI to initial state', () => {
      const modifiedState = {
        ...initialState,
        mediaUI: {
          showMyMixes: true,
          showCustomMixes: true,
          editingMixdownId: 'mix-456',
          creatingMixdown: true,
          createMixdownErrors: { error: 'Some error' }
        },
        mixerUI: {
          mixMode: 'MASTER',
          currentMixerRange: { min: 10, max: 90 }
        }
      };

      const actual = sessionUIReducer(modifiedState, resetUI());
      expect(actual.mediaUI).toEqual(initialState.mediaUI);
      expect(actual.mixerUI).toEqual(initialState.mixerUI);
    });
  });

  // Phase 5: Media UI selectors
  describe('media UI selectors', () => {
    const mockStateWithPhase5 = {
      sessionUI: {
        ...initialState,
        mediaUI: {
          showMyMixes: true,
          showCustomMixes: false,
          editingMixdownId: 'mix-789',
          creatingMixdown: true,
          createMixdownErrors: { name: 'Required' }
        },
        mixerUI: {
          mixMode: 'MASTER',
          currentMixerRange: { min: 20, max: 80 }
        }
      }
    };

    it('selectShowMyMixes should return correct value', () => {
      expect(selectShowMyMixes(mockStateWithPhase5)).toBe(true);
    });

    it('selectShowCustomMixes should return correct value', () => {
      expect(selectShowCustomMixes(mockStateWithPhase5)).toBe(false);
    });

    it('selectEditingMixdownId should return correct value', () => {
      expect(selectEditingMixdownId(mockStateWithPhase5)).toBe('mix-789');
    });

    it('selectCreatingMixdown should return correct value', () => {
      expect(selectCreatingMixdown(mockStateWithPhase5)).toBe(true);
    });

    it('selectCreateMixdownErrors should return correct value', () => {
      expect(selectCreateMixdownErrors(mockStateWithPhase5)).toEqual({ name: 'Required' });
    });

    it('selectMediaUI should return entire mediaUI object', () => {
      expect(selectMediaUI(mockStateWithPhase5)).toEqual(mockStateWithPhase5.sessionUI.mediaUI);
    });

    it('selectMixMode should return correct mix mode', () => {
      expect(selectMixMode(mockStateWithPhase5)).toBe('MASTER');
    });

    it('selectCurrentMixerRange should return correct range', () => {
      expect(selectCurrentMixerRange(mockStateWithPhase5)).toEqual({ min: 20, max: 80 });
    });

    it('selectMixerUI should return entire mixerUI object', () => {
      expect(selectMixerUI(mockStateWithPhase5)).toEqual(mockStateWithPhase5.sessionUI.mixerUI);
    });
  });

  // Recording state tests
  describe('recording actions', () => {
    it('should handle setRecordingStarted', () => {
      const actual = sessionUIReducer(initialState, setRecordingStarted('recording-123'));
      expect(actual.recording.isRecording).toBe(true);
      expect(actual.recording.recordingId).toBe('recording-123');
      expect(actual.recording.thisClientStartedRecording).toBe(true);
    });

    it('should handle setRecordingStopped', () => {
      const stateWithRecording = {
        ...initialState,
        recording: {
          isRecording: true,
          recordingId: 'recording-456',
          thisClientStartedRecording: true
        }
      };
      const actual = sessionUIReducer(stateWithRecording, setRecordingStopped());
      expect(actual.recording.isRecording).toBe(false);
      expect(actual.recording.recordingId).toBeNull();
      expect(actual.recording.thisClientStartedRecording).toBe(false);
    });

    it('should handle setRecordingStarted with different recording IDs', () => {
      let state = sessionUIReducer(initialState, setRecordingStarted('recording-1'));
      expect(state.recording.recordingId).toBe('recording-1');

      // Starting a new recording should update the ID
      state = sessionUIReducer(state, setRecordingStarted('recording-2'));
      expect(state.recording.recordingId).toBe('recording-2');
      expect(state.recording.isRecording).toBe(true);
    });

    it('should handle setRecordingStopped when not recording', () => {
      // Should handle gracefully even if not recording
      const actual = sessionUIReducer(initialState, setRecordingStopped());
      expect(actual.recording.isRecording).toBe(false);
      expect(actual.recording.recordingId).toBeNull();
    });
  });

  // Recording selectors tests
  describe('recording selectors', () => {
    const mockStateRecording = {
      sessionUI: {
        ...initialState,
        recording: {
          isRecording: true,
          recordingId: 'active-recording-789',
          thisClientStartedRecording: true
        }
      }
    };

    const mockStateNotRecording = {
      sessionUI: {
        ...initialState,
        recording: {
          isRecording: false,
          recordingId: null,
          thisClientStartedRecording: false
        }
      }
    };

    it('selectIsRecording should return true when recording', () => {
      expect(selectIsRecording(mockStateRecording)).toBe(true);
    });

    it('selectIsRecording should return false when not recording', () => {
      expect(selectIsRecording(mockStateNotRecording)).toBe(false);
    });

    it('selectRecordingId should return correct recording ID', () => {
      expect(selectRecordingId(mockStateRecording)).toBe('active-recording-789');
    });

    it('selectRecordingId should return null when not recording', () => {
      expect(selectRecordingId(mockStateNotRecording)).toBeNull();
    });

    it('selectThisClientStartedRecording should return true when this client started recording', () => {
      expect(selectThisClientStartedRecording(mockStateRecording)).toBe(true);
    });

    it('selectThisClientStartedRecording should return false when this client did not start recording', () => {
      expect(selectThisClientStartedRecording(mockStateNotRecording)).toBe(false);
    });
  });

  // Reset UI should also reset recording state
  describe('resetUI with recording state', () => {
    it('should reset recording state to initial values', () => {
      const stateWithRecording = {
        ...initialState,
        recording: {
          isRecording: true,
          recordingId: 'recording-to-reset',
          thisClientStartedRecording: true
        }
      };

      const actual = sessionUIReducer(stateWithRecording, resetUI());
      expect(actual.recording.isRecording).toBe(false);
      expect(actual.recording.recordingId).toBeNull();
      expect(actual.recording.thisClientStartedRecording).toBe(false);
    });
  });
});
