/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * Generated with the TypeScript template
 * https://github.com/react-native-community/react-native-template-typescript
 *
 * @format
 */

import React from 'react';
import {
  SafeAreaView,
  ScrollView,
  StatusBar,
  StyleSheet,
  Text,
  View,
  Switch,
  Button,
  Alert,
  PermissionsAndroid,
  // ToastAndroid,
  NativeModules,
} from 'react-native';

import BackgroundFetch from 'react-native-background-fetch';
import Geolocation, {
  GeolocationError,
  GeolocationResponse,
} from '@react-native-community/geolocation';

const {ForegroundHeadlessModule} = NativeModules;

const Colors = {
  gold: '#fedd1e',
  black: '#000',
  white: '#fff',
  lightGrey: '#ccc',
  blue: '#337AB7',
  brick: '#973920',
};

/// Util class for handling fetch-event peristence in AsyncStorage.
import Event from './src/Event';
import AsyncStorage from '@react-native-async-storage/async-storage';

Geolocation.setRNConfiguration({
  skipPermissionRequests: true,
  locationProvider: 'auto',
});

const requestPermissions = async () => {
  try {
    const granted = await PermissionsAndroid.request(
      PermissionsAndroid.PERMISSIONS.ACCESS_FINE_LOCATION,
      {
        title: 'Need permission to access location',
        message:
          'Location access is needed ' + 'so we can track your location!',
        buttonNegative: 'Cancel',
        buttonPositive: 'OK',
      },
    );
    const granted2 = await PermissionsAndroid.request(
      PermissionsAndroid.PERMISSIONS.ACCESS_BACKGROUND_LOCATION,
      {
        title: 'Need permission to access location',
        message:
          'Location access is needed ' + 'so we can track your location!',
        buttonNegative: 'Cancel',
        buttonPositive: 'OK',
      },
    );
    if (
      granted === PermissionsAndroid.RESULTS.GRANTED &&
      granted2 === PermissionsAndroid.RESULTS.GRANTED
    ) {
      console.log('You can use the location');
    } else {
      console.log('Location permission denied');
    }
  } catch (err) {
    console.warn(err);
  }
};

function geoLocationPromise(): Promise<GeolocationResponse | GeolocationError> {
  return new Promise((resolve, reject) => {
    Geolocation.getCurrentPosition(
      info => {
        console.log(info);
        resolve(info);
      },
      error => {
        console.log(error);
        reject(error);
      },
      {
        timeout: 20000,
        maximumAge: 0,
        // enableHighAccuracy: true,
      },
    );
  });
}

const App = () => {
  const [enabled, setEnabled] = React.useState(false);
  const [status, setStatus] = React.useState(-1);
  const [events, setEvents] = React.useState<Event[]>([]);

  React.useEffect(() => {
    async function asyncTask() {
      await requestPermissions();
      initBackgroundFetch();
      loadEvents();
    }

    asyncTask();
  }, []);

  /// Configure BackgroundFetch.
  ///
  const initBackgroundFetch = async () => {
    const status: number = await BackgroundFetch.configure(
      {
        minimumFetchInterval: 15, // <-- minutes (15 is minimum allowed)
        stopOnTerminate: false,
        enableHeadless: true,
        startOnBoot: false,
        // Android options
        forceAlarmManager: false, // <-- Set true to bypass JobScheduler.
        requiredNetworkType: BackgroundFetch.NETWORK_TYPE_NONE, // Default
        requiresCharging: false, // Default
        requiresDeviceIdle: false, // Default
        requiresBatteryNotLow: false, // Default
        requiresStorageNotLow: false, // Default
      },
      async (taskId: string) => {
        console.log('[BackgroundFetch] taskId', taskId);

        if (taskId === 'react-native-background-fetch') {
          // console.log('[BackgroundFetch] taskId', taskId);
          const event = await Event.create(taskId, false);
          // Update state.
          setEvents(prev => [...prev, event]);
        }

        if (taskId === 'com.transistorsoft.customtask') {
          // Geolocation.getCurrentPosition(
          //   async info => {
          //     console.log(info);
          //     const event = await Event.create(taskId, false, `lat-${info.coords.latitude};long-${info.coords.longitude}`);
          //   },
          //   err => console.log(err),
          //   {
          //     timeout: 10000,
          //     maximumAge: 10000,
          //     enableHighAccuracy: false,
          //   },
          // );
          try {
            const locInfo = (await geoLocationPromise()) as GeolocationResponse;
            const event = await Event.create(
              taskId,
              false,
              `lat-${locInfo.coords.latitude};long-${locInfo.coords.longitude}`,
            );
            // Update state.
            setEvents(prev => [...prev, event]);
          } catch (error) {
            const g = error as GeolocationError;
            if (g.message) {
              const event = await Event.create(taskId, false, `${g.message}`);
              // Update state.
              setEvents(prev => [...prev, event]);
            } else {
              const event = await Event.create(taskId, false);
              // Update state.
              setEvents(prev => [...prev, event]);
            }
          }
          // console.log('Running [customtask] here!');
        }

        // Finish.
        BackgroundFetch.finish(taskId);
      },
      (taskId: string) => {
        // Oh No!  Our task took too long to complete and the OS has signalled
        // that this task must be finished immediately.
        console.log('[Fetch] TIMEOUT taskId:', taskId);
        BackgroundFetch.finish(taskId);
      },
    );
    setStatus(status);
    setEnabled(true);
  };

  /// Load persisted events from AsyncStorage.
  ///
  const loadEvents = () => {
    Event.all()
      .then(data => {
        setEvents(data as Event[]);
      })
      .catch(error => {
        Alert.alert('Error', 'Failed to load data from AsyncStorage: ' + error);
      });
  };

  /// Toggle BackgroundFetch ON/OFF
  ///
  const onClickToggleEnabled = (value: boolean) => {
    setEnabled(value);

    if (value) {
      BackgroundFetch.start();
    } else {
      BackgroundFetch.stop();
    }
  };

  /// [Status] button handler.
  ///
  const onClickStatus = () => {
    BackgroundFetch.status().then((status: number) => {
      let statusConst = '';
      switch (status) {
        case BackgroundFetch.STATUS_AVAILABLE:
          statusConst = 'STATUS_AVAILABLE';
          break;
        case BackgroundFetch.STATUS_DENIED:
          statusConst = 'STATUS_DENIED';
          break;
        case BackgroundFetch.STATUS_RESTRICTED:
          statusConst = 'STATUS_RESTRICTED';
          break;
      }
      Alert.alert('BackgroundFetch.status()', `${statusConst} (${status})`);
    });
  };

  /// [scheduleTask] button handler.
  /// Schedules a custom-task to fire in 5000ms
  ///
  const onClickScheduleTask = () => {
    const delay = 600000;
    BackgroundFetch.scheduleTask({
      taskId: 'com.transistorsoft.customtask',
      stopOnTerminate: false,
      enableHeadless: true,
      delay: delay,
      forceAlarmManager: false,
      periodic: true,
    })
      .then(() => {
        Alert.alert(
          'scheduleTask',
          'Scheduled task with delay: ' + delay + 'ms',
        );
      })
      .catch(error => {
        Alert.alert('scheduleTask ERROR', error);
      });
  };

  /// Clear the Events list.
  ///
  const onClickClear = () => {
    Event.destroyAll();
    setEvents([]);
  };

  /// Fetch events renderer.
  ///
  const renderEvents = () => {
    if (!events.length) {
      return (
        <Text style={{padding: 10, fontSize: 16}}>
          Waiting for BackgroundFetch events...
        </Text>
      );
    }
    return events
      .slice()
      .reverse()
      .map(event => (
        <View key={event.key} style={styles.event}>
          <View style={{flexDirection: 'row'}}>
            <Text style={styles.taskId}>
              {event.taskId}&nbsp;{event.isHeadless ? '[Headless]' : ''}
            </Text>
          </View>
          <Text style={styles.remark}>Remark - {event.location}</Text>
          <Text style={styles.timestamp}>{event.timestamp}</Text>
        </View>
      ));
  };

  async function onLocPress(): Promise<void> {
    try {
      // const locInfo = (await geoLocationPromise()) as GeolocationResponse;
      // ToastAndroid.show(
      //   `lat-${locInfo.coords.latitude};long-${locInfo.coords.longitude}`,
      //   5000,
      // );
      ForegroundHeadlessModule.startService();
      console.log('Did it run?');
    } catch (error) {
      const g = error as GeolocationError;
      if (g.message) {
        console.log(g.message);
      } else {
        console.log(error);
      }
    }
  }

  function onLocStop() {
    ForegroundHeadlessModule.stopService();
    AsyncStorage.getItem('watchId', (err, result) => {
      if (err) {
        console.log('Couldnt get WatchID', err);
        return;
      }

      console.log(result);

      if (result) {
        Geolocation.clearWatch(+result);
      }
    });
  }

  return (
    <SafeAreaView style={{flex: 1, backgroundColor: Colors.gold}}>
      <StatusBar barStyle={'light-content'}></StatusBar>
      <View style={styles.container}>
        <View style={styles.toolbar}>
          <Text style={styles.title}>BGFetch Demo</Text>
          <Button title="Loc" onPress={onLocPress} />
          <Button title="Stop" onPress={onLocStop} />
          <Switch value={enabled} onValueChange={onClickToggleEnabled} />
        </View>
        <ScrollView
          contentInsetAdjustmentBehavior="automatic"
          style={styles.eventList}>
          {renderEvents()}
        </ScrollView>
        <View style={styles.toolbar}>
          <Button title={'status: ' + status} onPress={onClickStatus} />
          <Text>&nbsp;</Text>
          <Button title="scheduleTask" onPress={onClickScheduleTask} />
          <View style={{flex: 1}} />
          <Button title="clear" onPress={onClickClear} />
        </View>
      </View>
    </SafeAreaView>
  );
};

const styles = StyleSheet.create({
  container: {
    flexDirection: 'column',
    flex: 1,
  },
  title: {
    fontSize: 24,
    flex: 1,
    fontWeight: 'bold',
    color: Colors.black,
  },
  eventList: {
    flex: 1,
    backgroundColor: Colors.white,
  },
  event: {
    padding: 10,
    borderBottomWidth: 1,
    borderColor: Colors.lightGrey,
  },
  taskId: {
    color: Colors.blue,
    fontSize: 16,
    fontWeight: 'bold',
  },
  headless: {
    fontWeight: 'bold',
  },
  remark: {
    color: Colors.brick,
  },
  timestamp: {
    color: Colors.black,
  },
  toolbar: {
    height: 57,
    flexDirection: 'row',
    paddingLeft: 10,
    paddingRight: 10,
    alignItems: 'center',
    backgroundColor: Colors.gold,
  },
});

export default App;
