import { TranscriptionResult } from '@zocks-communications/client-sdk-js'
import transcriptReducer, {
  clearRemoteParticipantTranscription,
  clearTranscription,
  selectParticipantTranscripts,
  selectLocalStreamTranscriptionStatus,
  setDisplayTranscriptions,
  setTranscriptionInProgress,
  setTranscriptionServiceEnabled,
  setTranscriptionServiceIsLoading,
  transcriptionReceived,
} from './transcriptSlice'
import { SessionTranscriptModel } from './models'
import { mockRootState } from '../../testUtils'

beforeEach(() => jest.useFakeTimers().setSystemTime(new Date('2023-02-03T00:00:00.000Z')))

afterEach(() => jest.useRealTimers())

const mockTranscriptionResult: TranscriptionResult = {
  resultId: 'testResultId',
  createdAt: '2023-02-03T00:00:00.000Z',
  isFinal: true,
  startTime: 0,
  endTime: 2,
  transcript: 'test',
  items: [
    {
      content: 'test',
      isStable: true,
    },
  ],
}

test('handles receiving final transcription results', () => {
  const state: SessionTranscriptModel = {
    localStreamTranscriptionStatus: {
      serviceEnabled: true,
      serviceLoading: false,
      autoEnabled: false,
      transcriptionInProgress: true,
    },
    displayTranscriptions: false,
    transcripts: {},
  }

  const newState = transcriptReducer(
    state,
    transcriptionReceived({ participantId: 'testLocalParticipantId', transcriptionResult: mockTranscriptionResult })
  )

  expect(newState).toStrictEqual({
    ...state,
    transcripts: {
      testLocalParticipantId: {
        partialTranscript: null,
        finalTranscripts: [mockTranscriptionResult],
      },
    },
  })
})
test('handles receiving partial transcription results', () => {
  const state: SessionTranscriptModel = {
    localStreamTranscriptionStatus: {
      serviceEnabled: true,
      serviceLoading: false,
      autoEnabled: false,
      transcriptionInProgress: true,
    },
    displayTranscriptions: false,
    transcripts: {},
  }

  const newState = transcriptReducer(
    state,
    transcriptionReceived({
      participantId: 'testLocalParticipantId',
      transcriptionResult: { ...mockTranscriptionResult, isFinal: false },
    })
  )

  expect(newState).toStrictEqual({
    ...state,
    transcripts: {
      testLocalParticipantId: {
        partialTranscript: { ...mockTranscriptionResult, isFinal: false },
        finalTranscripts: [],
      },
    },
  })
})
test('handles receiving transcription results for a participant with already existing results', () => {
  const state: SessionTranscriptModel = {
    localStreamTranscriptionStatus: {
      serviceEnabled: true,
      serviceLoading: false,
      autoEnabled: false,
      transcriptionInProgress: true,
    },
    displayTranscriptions: false,
    transcripts: {
      testLocalParticipantId: {
        partialTranscript: { ...mockTranscriptionResult, isFinal: false },
        finalTranscripts: [],
      },
    },
  }

  const newState = transcriptReducer(
    state,
    transcriptionReceived({
      participantId: 'testLocalParticipantId',
      transcriptionResult: { ...mockTranscriptionResult },
    })
  )

  expect(newState).toStrictEqual({
    ...state,
    transcripts: {
      testLocalParticipantId: {
        partialTranscript: null,
        finalTranscripts: [mockTranscriptionResult],
      },
    },
  })
})

test('handles transcription service enabled state changes', () => {
  const state: SessionTranscriptModel = {
    localStreamTranscriptionStatus: {
      serviceEnabled: true,
      serviceLoading: false,
      autoEnabled: false,
      transcriptionInProgress: true,
    },
    displayTranscriptions: false,
    transcripts: {},
  }

  const newState = transcriptReducer(state, setTranscriptionServiceEnabled({ enabled: false }))

  expect(newState.localStreamTranscriptionStatus.serviceEnabled).toBe(false)
})

test('handles transcription service autoEnabled state changes', () => {
  const state: SessionTranscriptModel = {
    localStreamTranscriptionStatus: {
      serviceEnabled: false,
      serviceLoading: false,
      autoEnabled: false,
      transcriptionInProgress: true,
    },
    displayTranscriptions: false,
    transcripts: {},
  }

  const newState = transcriptReducer(state, setTranscriptionServiceEnabled({ enabled: true, autoEnable: true }))

  expect(newState.localStreamTranscriptionStatus.serviceEnabled).toBe(true)
  expect(newState.localStreamTranscriptionStatus.autoEnabled).toBe(true)
})

test('handles transcription service loading state changes', () => {
  const state: SessionTranscriptModel = {
    localStreamTranscriptionStatus: {
      serviceEnabled: true,
      serviceLoading: false,
      autoEnabled: false,
      transcriptionInProgress: true,
    },
    displayTranscriptions: false,
    transcripts: {},
  }

  const newState = transcriptReducer(state, setTranscriptionServiceIsLoading(true))

  expect(newState.localStreamTranscriptionStatus.serviceLoading).toBe(true)
})

test('handles transcription in progress state changes', () => {
  const state: SessionTranscriptModel = {
    localStreamTranscriptionStatus: {
      serviceEnabled: true,
      serviceLoading: false,
      autoEnabled: false,
      transcriptionInProgress: false,
    },
    displayTranscriptions: false,
    transcripts: {},
  }

  const newState = transcriptReducer(state, setTranscriptionInProgress(true))

  expect(newState.localStreamTranscriptionStatus.transcriptionInProgress).toBe(true)
})

test('handles display transcription state changes', () => {
  const state: SessionTranscriptModel = {
    localStreamTranscriptionStatus: {
      serviceEnabled: true,
      serviceLoading: false,
      autoEnabled: false,
      transcriptionInProgress: false,
    },
    displayTranscriptions: false,
    transcripts: {},
  }

  const newState = transcriptReducer(state, setDisplayTranscriptions(true))

  expect(newState.displayTranscriptions).toBe(true)
})

test('clears partial transcriptions when transcription is not in progress anymore', () => {
  const state: SessionTranscriptModel = {
    localStreamTranscriptionStatus: {
      serviceEnabled: true,
      serviceLoading: false,
      autoEnabled: false,
      transcriptionInProgress: true,
    },
    displayTranscriptions: false,
    transcripts: {
      testLocalParticipantId: {
        partialTranscript: mockTranscriptionResult,
        finalTranscripts: [],
      },
    },
  }

  const newState = transcriptReducer(state, setTranscriptionInProgress(false))

  expect(newState.transcripts.testLocalParticipantId.partialTranscript).toBeNull()
})

test('clears transcriptions for everyone and disables transcription service', () => {
  const state: SessionTranscriptModel = {
    localStreamTranscriptionStatus: {
      serviceEnabled: true,
      serviceLoading: false,
      autoEnabled: false,
      transcriptionInProgress: true,
    },
    displayTranscriptions: false,
    transcripts: {
      testLocalParticipantId: {
        partialTranscript: mockTranscriptionResult,
        finalTranscripts: [],
      },
      testRemoteParticipantId: {
        partialTranscript: null,
        finalTranscripts: [mockTranscriptionResult],
      },
    },
  }

  const newState = transcriptReducer(state, clearTranscription())

  expect(newState).toStrictEqual({
    localStreamTranscriptionStatus: {
      serviceEnabled: false,
      serviceLoading: false,
      autoEnabled: false,
      transcriptionInProgress: true,
    },
    displayTranscriptions: false,
    transcripts: {},
  })
})

test('clears transcriptions for a specific remote participant', () => {
  const state: SessionTranscriptModel = {
    localStreamTranscriptionStatus: {
      serviceEnabled: true,
      serviceLoading: false,
      autoEnabled: false,
      transcriptionInProgress: true,
    },
    displayTranscriptions: false,
    transcripts: {
      testLocalParticipantId: {
        partialTranscript: mockTranscriptionResult,
        finalTranscripts: [],
      },
      testRemoteParticipantId: {
        partialTranscript: null,
        finalTranscripts: [mockTranscriptionResult],
      },
    },
  }

  const newState = transcriptReducer(
    state,
    clearRemoteParticipantTranscription({ participantId: 'testRemoteParticipantId' })
  )

  expect(newState).toStrictEqual({
    localStreamTranscriptionStatus: {
      serviceEnabled: true,
      serviceLoading: false,
      autoEnabled: false,
      transcriptionInProgress: true,
    },
    displayTranscriptions: false,
    transcripts: {
      testLocalParticipantId: {
        partialTranscript: mockTranscriptionResult,
        finalTranscripts: [],
      },
    },
  })
})

test('selectParticipantTranscripts selects the transcripts of the participant if they have transcripts', () => {
  const state: SessionTranscriptModel = {
    localStreamTranscriptionStatus: {
      serviceEnabled: true,
      serviceLoading: false,
      autoEnabled: false,
      transcriptionInProgress: true,
    },
    displayTranscriptions: false,
    transcripts: {
      testLocalParticipantId: {
        partialTranscript: mockTranscriptionResult,
        finalTranscripts: [mockTranscriptionResult],
      },
    },
  }

  const selectedTranscripts = selectParticipantTranscripts(
    { ...mockRootState, transcript: state },
    'testLocalParticipantId'
  )

  expect(selectedTranscripts).toStrictEqual({
    partialTranscript: mockTranscriptionResult,
    finalTranscripts: [mockTranscriptionResult],
  })
})

test('selectParticipantTranscripts selects empty transcripts if the participant does not have transcripts yet', () => {
  const state: SessionTranscriptModel = {
    localStreamTranscriptionStatus: {
      serviceEnabled: true,
      serviceLoading: false,
      autoEnabled: false,
      transcriptionInProgress: true,
    },
    displayTranscriptions: false,
    transcripts: {},
  }

  const selectedTranscripts = selectParticipantTranscripts(
    { ...mockRootState, transcript: state },
    'testLocalParticipantId'
  )

  expect(selectedTranscripts).toStrictEqual({
    partialTranscript: null,
    finalTranscripts: [],
  })
})

test('selectParticipantTranscripts selects the transcripts since the given seconds', () => {
  const state: SessionTranscriptModel = {
    localStreamTranscriptionStatus: {
      serviceEnabled: true,
      serviceLoading: false,
      autoEnabled: false,
      transcriptionInProgress: true,
    },
    displayTranscriptions: false,
    transcripts: {
      testLocalParticipantId: {
        partialTranscript: mockTranscriptionResult,
        finalTranscripts: [
          { ...mockTranscriptionResult, createdAt: '2023-02-02T23:59:55.000Z' },
          { ...mockTranscriptionResult, createdAt: '2023-02-02T23:59:56.000Z' },
        ],
      },
    },
  }

  const selectedTranscripts = selectParticipantTranscripts(
    { ...mockRootState, transcript: state },
    'testLocalParticipantId',
    5
  )

  expect(selectedTranscripts).toStrictEqual({
    partialTranscript: mockTranscriptionResult,
    finalTranscripts: [{ ...mockTranscriptionResult, createdAt: '2023-02-02T23:59:56.000Z' }],
  })
})

test('selectLocalStreamTranscriptionStatus selects local stream transcription status', () => {
  const state: SessionTranscriptModel = {
    localStreamTranscriptionStatus: {
      serviceEnabled: true,
      serviceLoading: false,
      autoEnabled: false,
      transcriptionInProgress: true,
    },
    displayTranscriptions: false,
    transcripts: {},
  }

  expect(selectLocalStreamTranscriptionStatus({ ...mockRootState, transcript: state })).toStrictEqual({
    serviceEnabled: true,
    serviceLoading: false,
    autoEnabled: false,
    transcriptionInProgress: true,
  })
})
