import React from 'react';
import { render, screen, fireEvent, waitFor, act } from '@testing-library/react';
import { Provider } from 'react-redux';
import { configureStore } from '@reduxjs/toolkit';
import JKSessionRecordingModal from '../JKSessionRecordingModal';
import sessionUIReducer from '../../../store/features/sessionUISlice';

// Mock dependencies
jest.mock('react-toastify', () => ({
  toast: {
    info: jest.fn(),
    error: jest.fn(),
    warning: jest.fn(),
  },
}));

const mockJamClient = {
  GetAudioRecordingPreference: jest.fn().mockResolvedValue(2),
  SetAudioRecordingPreference: jest.fn().mockResolvedValue(true),
  getOpenVideoSources: jest.fn().mockResolvedValue({
    webcam1: true,
    webcam2: false,
    screen_capture: true,
    session_video: false,
  }),
  IsOBSAvailable: jest.fn().mockResolvedValue(false),
};

jest.mock('../../../context/JamServerContext', () => ({
  useJamServerContext: () => ({
    jamClient: mockJamClient,
  }),
}));

jest.mock('../../../hooks/useRecordingHelpers', () => () => ({
  currentlyRecording: false,
  startingRecording: false,
  stoppingRecording: false,
  startRecording: jest.fn().mockResolvedValue({ id: 'test-recording-id' }),
  stopRecording: jest.fn().mockResolvedValue(true),
}));

// Create a mock store
const createMockStore = (initialState = {}) => {
  return configureStore({
    reducer: {
      sessionUI: sessionUIReducer,
    },
    preloadedState: {
      sessionUI: {
        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,
        },
        mediaUI: {
          showMyMixes: false,
          showCustomMixes: false,
          editingMixdownId: null,
          creatingMixdown: false,
          createMixdownErrors: null,
        },
        mixerUI: {
          mixMode: 'PERSONAL',
          currentMixerRange: { min: null, max: null },
        },
        openJamTrack: null,
        jamTrackUI: {
          lastUsedMixdownId: null,
          volume: 100,
        },
        recording: {
          isRecording: false,
          recordingId: null,
          thisClientStartedRecording: false,
        },
        ...initialState,
      },
    },
  });
};

// Helper function for rendering component with providers
const renderModal = async (props = {}, storeState = {}) => {
  const store = createMockStore(storeState);
  const defaultProps = {
    isOpen: true,
    toggle: jest.fn(),
  };

  let result;
  await act(async () => {
    result = render(
      <Provider store={store}>
        <JKSessionRecordingModal {...defaultProps} {...props} />
      </Provider>
    );
  });

  return {
    ...result,
    store,
  };
};

describe('JKSessionRecordingModal', () => {
  beforeEach(() => {
    jest.clearAllMocks();
  });

  describe('rendering', () => {
    test('renders modal with title "Make Recording"', async () => {
      await renderModal();
      expect(screen.getByText('Make Recording')).toBeInTheDocument();
    });

    test('renders recording type radio buttons', async () => {
      await renderModal();
      expect(screen.getByLabelText('Audio only')).toBeInTheDocument();
      expect(screen.getByLabelText('Audio and video')).toBeInTheDocument();
    });

    test('renders name input field', async () => {
      await renderModal();
      expect(screen.getByPlaceholderText('Recording Name')).toBeInTheDocument();
    });

    test('renders Start Recording button when not recording', async () => {
      await renderModal();
      expect(screen.getByRole('button', { name: /start recording/i })).toBeInTheDocument();
    });

    test('renders Close button', async () => {
      await renderModal();
      // There are two close buttons - X in header and Close in footer
      const closeButtons = screen.getAllByRole('button', { name: /close/i });
      expect(closeButtons.length).toBe(2);
    });
  });

  describe('name validation', () => {
    test('shows error when trying to start recording with empty name', async () => {
      await renderModal();

      const startButton = screen.getByRole('button', { name: /start recording/i });

      await act(async () => {
        fireEvent.click(startButton);
        // Allow state updates to complete
        await new Promise(resolve => setTimeout(resolve, 100));
      });

      expect(screen.getByText('Please enter a recording name.')).toBeInTheDocument();
    });

    test('shows error when name contains only whitespace', async () => {
      await renderModal();

      const nameInput = screen.getByPlaceholderText('Recording Name');
      fireEvent.change(nameInput, { target: { value: '   ' } });

      const startButton = screen.getByRole('button', { name: /start recording/i });

      await act(async () => {
        fireEvent.click(startButton);
        // Allow state updates to complete
        await new Promise(resolve => setTimeout(resolve, 100));
      });

      expect(screen.getByText('Please enter a recording name.')).toBeInTheDocument();
    });
  });

  describe('recording type selection', () => {
    test('audio only is selected by default', async () => {
      await renderModal();
      const audioOnlyRadio = screen.getByLabelText('Audio only');
      expect(audioOnlyRadio).toBeChecked();
    });
  });

  describe('close functionality', () => {
    test('calls toggle when Close button is clicked', async () => {
      const toggleMock = jest.fn();
      await renderModal({ toggle: toggleMock });

      // Get the Close button in the footer (second one, or by text content)
      const closeButtons = screen.getAllByRole('button', { name: /close/i });
      const footerCloseButton = closeButtons.find(btn => btn.textContent === 'Close');
      fireEvent.click(footerCloseButton);

      expect(toggleMock).toHaveBeenCalledTimes(1);
    });
  });

  describe('form state management', () => {
    test('can change recording name', async () => {
      await renderModal();
      const nameInput = screen.getByPlaceholderText('Recording Name');

      fireEvent.change(nameInput, { target: { value: 'Test Recording' } });

      expect(nameInput.value).toBe('Test Recording');
    });

    test('can toggle voice chat checkbox', async () => {
      await renderModal();
      const voiceChatCheckbox = screen.getByLabelText('Include voice chat in recording');

      expect(voiceChatCheckbox).not.toBeChecked();
      fireEvent.click(voiceChatCheckbox);
      expect(voiceChatCheckbox).toBeChecked();
    });
  });

  describe('modal visibility', () => {
    test('does not render content when isOpen is false', async () => {
      await renderModal({ isOpen: false });
      expect(screen.queryByText('Make Recording')).not.toBeInTheDocument();
    });

    test('renders content when isOpen is true', async () => {
      await renderModal({ isOpen: true });
      expect(screen.getByText('Make Recording')).toBeInTheDocument();
    });
  });
});
