import React from 'react';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import YounifyServices from './YounifyServices';
import YounifyCategories from './YounifyCategories';
import YounifyBrowse from './YounifyBrowse';
import YounifyDetails from './YounifyDetails'

import
{
  StyleSheet,
  SafeAreaView,
  Linking,
} from 'react-native';

import
{
  Connect,
  LogLevel,
  type LogListener,
  type TokenHandler,
  type ConnectOptions,
} from 'react-native-younify-connect-sdk';

export default function App()
{
  const connect = Connect.shared;
  const younifyServicesRef = React.useRef<any>();
  const younifyCategoriesRef = React.useRef<any>();
  const younifyBrowseRef = React.useRef<any>();
  const younifyDetailsRef = React.useRef<any>();
  const Tab = createBottomTabNavigator();

  React.useEffect(() =>
  {
    (async () =>
    {
      const at = await AsyncStorage.getItem('ycs.at');
      const rt = await AsyncStorage.getItem('ycs.rt');

      const options: ConnectOptions =
      {
        //TODO: Set your app key.
        key: '_YOUR_APP_KEY_HERE_',
        logLevel: LogLevel.Warning,
        logListener: { onMessage(level: LogLevel, message: string) { console.log("log message: " + LogLevel[level] + ' ' + message); } } as LogListener,
        tokenHandler: new class implements TokenHandler
        {
          onRenew(_expiredAccessToken: string | null, _refreshToken: string | null, renewed: (newAccessToken: string | null, newRefreshToken: string | null) => void): void
          {
            //TODO: Implement this method to perform a backend token renewal by proxying the request
            //to your own backend servers, then to Younify using your private api key.
            renewed(null, null);
          }

          onRenewed(newAccessToken: string, newRefreshToken: string): void
          {
            AsyncStorage.setItem('ycs.at', newAccessToken);
            AsyncStorage.setItem('ycs.rt', newRefreshToken);
          }
        },
        accessToken: at,
        refreshToken: rt,
        extra: null
      }

      await connect.configure(options);

      const handleLink = async (uri: string) =>
      {
        try
        {
          const url = new URL(uri);

          //TODO: Remove the following block, scheme based intent-filter in AndroidManifest.xml and CFBundleURLTypes scheme entry in Info.plist for production apps!
          //The following block allows configuring the Younify Connect SDK from a url in order to facilitate testing.
          //The url format is ycssampleapp://configure/?key=<sdk key>&at=<user's access token>&rt=<user's refresh token>.
          if (url.protocol === 'ycssampleapp:')
          {
            if (url.host === 'configure')
            {
              const searchParams = url.searchParams;
              const key = searchParams.get('key');
              const at = searchParams.get('at');
              const rt = searchParams.get('rt');
              const extra = searchParams.get('extra');

              let extraObject: object | null = null;
              try { extraObject = extra ? JSON.parse(extra) : null; }
              catch (e) { }

              if (key && at && rt)
              {
                options.key = key;
                options.tokenHandler = null; //XXX: Because the key isn't being persisted, prevent token renewals from being persisted as well.
                options.accessToken = at;
                options.refreshToken = rt;
                options.extra = extraObject;
                await connect.configure(options);
                await younifyServicesRef.current?.fetchServices();
              }
            }
          }
        }
        catch (e)
        {
        }
      };

      const initialUrl = await Linking.getInitialURL();
      if (initialUrl)
        await handleLink(initialUrl);

      Linking.addEventListener('url', async (o) => await handleLink(o.url));

      await younifyServicesRef.current?.fetchServices();
    })();

    return () =>
    {
      // this now gets called when the component unmounts
    };
  }, []);

  const ServicesScreen = ({ navigation }: any) =>
  {
    return (
      <YounifyServices
        ref={ younifyServicesRef }
        onBrowseRequest={ (services) =>
        {
          navigation.navigate('Categories');
          younifyCategoriesRef.current?.fetchContent(services);
        }}/>
    );
  };

  const CategoriesScreen = ({ navigation }: any) =>
  {
    return (
      <YounifyCategories
        ref={ younifyCategoriesRef }
        onBrowseRequest={ (contentItem) =>
        {
          navigation.navigate('Browse');
          younifyBrowseRef.current?.browseContent(contentItem);
        }}
        onServiceChanged={ (service) =>
        {
          younifyServicesRef.current?.updateService(service);
        }}
        onSearchRequest={ (services, searchTerm) =>
        {
          navigation.navigate('Browse');
          younifyBrowseRef.current?.searchContent(services, searchTerm);
        }}
      />
    );
  };

  const BrowseScreen = ({ navigation }: any) =>
  {
    return (
      <YounifyBrowse
        ref={ younifyBrowseRef }
        onServiceUpdateRequest={ (service) =>
        {
          younifyServicesRef.current?.updateService(service);
        }}
        onDetailsRequest={ (item) =>
        {
          navigation.navigate('Details');
          younifyDetailsRef.current?.getDetails(item);
        }}/>
    );
  };

  const DetailsScreen = () =>
  {
    return (
      <YounifyDetails
        ref={ younifyDetailsRef }/>
    );
  };

  return (
    <SafeAreaView style={ styles.container }>
      <NavigationContainer>
        <Tab.Navigator
          screenOptions={{ tabBarStyle: styles.tabBarStyle, headerShown: false }}
          backBehavior={ 'history' }>

          <Tab.Screen
            name="Services"
            options={{ lazy: false }}
            component={ ServicesScreen }/>

          <Tab.Screen
            name="Categories"
            options={{ lazy: false }}
            component= { CategoriesScreen }/>

          <Tab.Screen
            name="Browse"
            options={{ lazy: false }}
            component= { BrowseScreen }/>

          <Tab.Screen
            name="Details"
            options={{ lazy: false }}
            component= { DetailsScreen }/>

        </Tab.Navigator>
      </NavigationContainer>
    </SafeAreaView>
  );
}

const styles = StyleSheet.create
(
  {
    tabBarStyle:
    {
      display: 'none'
    },
    container:
    {
      flex: 1,
      alignItems: 'stretch',
      justifyContent: 'center'
    }
  }
);
