import {
  OptimizationNavigationContainer,
  type OptimizationNavigationContainerProps,
  useOptimization,
} from '@contentful/optimization-react-native'
import type { NavigationContainerRef } from '@react-navigation/native'
import { NavigationContainer, NavigationIndependentTree } from '@react-navigation/native'
import {
  createNativeStackNavigator,
  type NativeStackNavigationProp,
} from '@react-navigation/native-stack'
import React, { useEffect, useRef, useState } from 'react'
import { Button, View } from 'react-native'
import type {
  NavigationTestScreenProps,
  NavigationTestStackParamList,
} from '../types/navigationTypes'
import { adaptNavigationState, isScreenViewEvent, toRecord } from '../utils/navigationHelpers'
import { ImplementationNavigationView } from './ImplementationNavigationView'
import { NavigationHome } from './NavigationHome'

const Stack = createNativeStackNavigator<NavigationTestStackParamList>()

function NavigationContainerTracking(props: OptimizationNavigationContainerProps): React.ReactNode {
  return OptimizationNavigationContainer(props)
}

export function NavigationTestScreen({ onClose }: NavigationTestScreenProps): React.JSX.Element {
  const navigationRef = useRef<NavigationContainerRef<NavigationTestStackParamList>>(null)
  const contentfulOptimization = useOptimization()
  const [screenEventLog, setScreenEventLog] = useState<string[]>([])
  const lastScreenEventName = screenEventLog.at(-1)

  const renderNavigationView = ({
    testIdSuffix,
    nextButtonTitle,
    nextButtonTestId,
    onNavigateNext,
  }: {
    testIdSuffix: string
    nextButtonTitle: string
    nextButtonTestId: string
    onNavigateNext?: () => void
  }): React.JSX.Element => (
    <ImplementationNavigationView
      testIdSuffix={testIdSuffix}
      lastScreenEventName={lastScreenEventName}
      screenEventLog={screenEventLog}
      onNavigateNext={onNavigateNext}
      nextButtonTitle={nextButtonTitle}
      nextButtonTestId={nextButtonTestId}
    />
  )

  useEffect(() => {
    const subscription = contentfulOptimization.states.eventStream.subscribe((event: unknown) => {
      if (isScreenViewEvent(event)) {
        setScreenEventLog((prev) => [...prev, event.name])
      }
    })

    return () => {
      subscription.unsubscribe()
    }
  }, [contentfulOptimization])

  return (
    <View style={{ flex: 1 }}>
      <View>
        <Button testID="close-navigation-test-button" title="Close" onPress={onClose} />
      </View>
      <NavigationContainerTracking>
        {(navigationProps) => (
          <NavigationIndependentTree>
            <NavigationContainer
              ref={navigationRef}
              onReady={() => {
                const route = navigationRef.current?.getCurrentRoute()
                if (route) {
                  Object.assign(navigationProps.ref, {
                    current: {
                      getCurrentRoute: () => ({
                        name: route.name,
                        params: toRecord(route.params),
                      }),
                    },
                  })
                }
                navigationProps.onReady()
              }}
              onStateChange={(state) => {
                const route = navigationRef.current?.getCurrentRoute()
                if (route) {
                  Object.assign(navigationProps.ref, {
                    current: {
                      getCurrentRoute: () => ({
                        name: route.name,
                        params: toRecord(route.params),
                      }),
                    },
                  })
                }
                navigationProps.onStateChange(adaptNavigationState(state))
              }}
            >
              <Stack.Navigator screenOptions={{ headerShown: false }}>
                <Stack.Screen name="NavigationHome" component={NavigationHome} />
                <Stack.Screen name="NavigationViewOne">
                  {({
                    navigation,
                  }: {
                    navigation: NativeStackNavigationProp<
                      NavigationTestStackParamList,
                      'NavigationViewOne'
                    >
                  }) =>
                    renderNavigationView({
                      testIdSuffix: 'one',
                      nextButtonTitle: 'Go to View Two',
                      nextButtonTestId: 'go-to-view-two-button',
                      onNavigateNext: () => {
                        navigation.navigate('NavigationViewTwo')
                      },
                    })
                  }
                </Stack.Screen>
                <Stack.Screen name="NavigationViewTwo">
                  {() =>
                    renderNavigationView({
                      testIdSuffix: 'two',
                      nextButtonTitle: 'Go to View Two',
                      nextButtonTestId: 'go-to-view-two-button',
                    })
                  }
                </Stack.Screen>
              </Stack.Navigator>
            </NavigationContainer>
          </NavigationIndependentTree>
        )}
      </NavigationContainerTracking>
    </View>
  )
}
