import {
  NativeModules,
  NativeEventEmitter,
  Platform,
  Linking,
  Alert,
  EmitterSubscription,
} from 'react-native';

const {
  BEACON_PRIORITY_FAST,
  BEACON_PRIORITY_OPTIMAL,
  BEACON_PRIORITY_SLOW,
  BEACON_PRIORITY_DRIVING
} = NativeModules.MapplsIntouch.getConstants();

interface CustomConfigParams {
  enableAutoStartTracking?: boolean;
  beaconStartTimeInSec?: number;
  beaconEndTimeInSec?: number;
  timeWhileMovingInSec: number;
  standByTimeInMins: number;
  timeDelayFromMovingToStopInMillis?: number;
  displacement?: number;
  defaultAccuracy?: number;
  activityDetectionTimeInterval?: number;
  enableRequestPermissionIfMissing?: boolean;
  isAccelerometerSensorRequired?: boolean;
  isGyroMeterSensorRequired?: boolean;
  isProximitySensorRequired?: boolean;
  isBarometerSensorRequired?: boolean;
  isTemperatureSensorRequired?: boolean;
  isLightSensorRequired?: boolean;
  isPhoneStateListenerRequired?: boolean;
  isDrivingMode?: boolean;
  autoTrackingConfig?: AutoTrackingConfig;
}

interface ConfigParams {
  priority?: number;
  enableRequestPermissionIfMissing?: boolean;
  activityDetectionTimeInterval?: number;
  isGNSSFullTrackingEnable?: boolean;
  isWaitForAccurateLocation?: boolean;
}

interface AutoTrackingConfig {
  endTimeConfig: WorkTiming;
}

interface WorkTiming {
  hour: number;
  minute: number;
  second: number; 
  amPm: string;
}

interface InitializeApisSdkProps {
  mapSDKKey: string;
  restAPIKey: string;
  clientId: string;
  clientSecret: string;
}

interface DeviceStateListenerProps {
  onBatteryChange?(batteryInfo: number): Function;
  onDeviceStateChange?(deviceState: number): Function;
  isGprsAvailable?(isGprs: boolean): Function;
  isGpsAvailable?(isGPS: boolean): Function;
}

interface GetDevicesProps {
  deviceIds?: Array<Number>;
  includeInActive?: boolean;
  ignoreBeacon?: boolean;
  lastUpdateTime: number;
}

interface GetDeviceProps {
  deviceId: number;
  lastUpdateTime: number;
}

interface GetDeviceInfoProps {
  deviceIds?: Array<Number>;
}

interface GetLocationEventsProps {
  deviceId: number;
  startTime: number;
  endTime: number;
  skipPeriod: number;
}
interface GetDriveProps {
  deviceId: number;
  startTime: number;
  endTime: number;
}

interface CreateGeoFenceProps {
  geofenceName: string;
  geofencePoints?: Array<[number, number]>;
  geofencePoint?: [number, number];
  range?: number;
}

interface GetGeoFencesProps {
  ignoreGeometry: boolean;
  geofenceIds?: Array<number>;
  geofenceId?: number;
}

interface UpdateGeofenceProps {
  geofenceId: number;
  geofenceName: string;
  geofencePoint?: [number, number];
  geofencePoints?: Array<[number, number]>;
  buffer?: number;
}

interface DeleteGeoFenceProps {
  geofenceIds?: Array<number>;
  geofenceId?: number;
}
interface GetGeoFenceActivity {
  deviceIds: Array<number>;
  startTime: number;
  endTime: number;
  geofenceIds?: Array<number>;
}
interface CreateTripProps {
  tripName: string;
  deviceId: number;
  isForceCloseEnable: boolean;
  scheduleEndTime?: number;
  tripDestination?: TripDestination;
  metaData: Object;
  tripGeofences?: Array<TripGeofence>;
}
interface TripDestination {
  metaData: Object;
  scheduledAt: number;
  radius: number;
  geometry: Geometry;
}

interface TripGeofence {
  radius: number;
  scheduledAt: number;
  metaData: Object;
  geometry: Geometry;
}
interface Geometry {
  type: string;
  coordinates: Array<[number, number]>; //array of lat & lng
}
interface GetTripsProps {
  deviceIds?: Array<number>;
  limit?: number;
  status?: number;
  statTimeStamp?: number;
  endTimeStamp?: number;
}

interface GetTripInfoProps {
  tripId: String;
  isPositionEventsEnable?: boolean;
  isLocationEnable?: boolean;
  isPolylineEnable?: boolean;
}
interface CloseTripProps {
  tripId: string;
}
interface CreateAlarmProps {
  alarmParameters: CreateAlarmParamsProps;
}
interface CreateAlarmParamsProps {
  deviceId: Array<number>;
  type?: number;
  duration?: number;
  limit?: number;
  geofenceId: Array<number>;
  alarmType?: number;
}
interface GetAlarmConfigsProps {
  alarmIds?: Array<number>;
  deviceIds?: Array<number>;
  alarmTypes?: Array<number>;
}
interface UpdateAlaramProps {
  alarmId: number;
  alarmParameters: UpdateAlarmParamsProps;
}

interface UpdateAlarmParamsProps {
  deviceId?: number;
  type?: number;
  duration?: number;
  limit?: number;
  geofenceId?: number;
  alarmType?: number;
  // alarmId?:number;
}

interface DeleteAlarmProps {
  alarmIds?: Array<number>;
  alarmId?: number;
}

interface GetAlarmLogsProps {
  deviceIds?: Array<number>;
  alarmTypes?: Array<number>;
  startTime: number;
  endTime: number;
}
var MapplsIntouch = {
  initialize: async function (
    deviceName: string,
    clientId: string,
    clientSecret: string,
  ) {
    if (deviceName && clientId && clientSecret) {
      return await NativeModules.MapplsIntouch.createDevice(
        deviceName,
        clientId,
        clientSecret,
        '',
      );
    } else {
      error('please provide device Name or required keys');
    }
  },

  initializeWithDeviceId: async function (
    deviceName: string,
    clientId: string,
    clientSecret: string,
    deviceCode: string,
  ) {
    if (deviceName && clientId && clientSecret && deviceCode) {
      return await NativeModules.MapplsIntouch.createDevice(
        deviceName,
        clientId,
        clientSecret,
        deviceCode,
      );
    } else {
      error('please provide required parameters');
    }
  },

  isInitialized: async function () {
    const status = await NativeModules.MapplsIntouch.isInitialized();
    if (Platform.OS === 'ios') {
      return status > 0 ? true : false;
    } else {
      return status;
    }
  },

  startTracking: async function (props: ConfigParams) {
    NativeModules.MapplsIntouch.startTracking(props);
  },

  startTrackingWithCustomConfig: async function (props: CustomConfigParams) {
    if (props.standByTimeInMins && props.timeWhileMovingInSec) {
      NativeModules.MapplsIntouch.startTrackingWithCustomConfig(props);
    } else {
      error('Please pass required parameters to start custom tracking');
    }
  },

  stopTracking: function () {
    NativeModules.MapplsIntouch.stopTracking();
  },

  addTrackingStateListener: (listenerEvent: Function, error: Function) => {
    NativeModules.MapplsIntouch.addTrackingStateListener();
    const eventEmitter = new NativeEventEmitter(
      NativeModules.MapplsIntouch,
    );
    const eventListener = eventEmitter.addListener(
      'TrackingStateListener',
      (event) => {
        if (
          Platform.OS === 'ios' &&
          event === 'Location services are not enabled'
        ) {
          listenerEvent('please enable location permissions and services');
          iosSettingsAlert();
        } else {
          listenerEvent(event);
        }
      },
    );

    var errorListener = eventEmitter.addListener(
      'TrackingErrorListener',
      (event) => {
        error(event);
      },
    );
    return [eventListener, errorListener];
  },

  addDeviceStateChangeListener: (props: DeviceStateListenerProps) => {
    NativeModules.MapplsIntouch.addDeviceStateChangeListener();
    const eventEmitter = new NativeEventEmitter(
      NativeModules.MapplsIntouch,
    );
    new NativeEventEmitter(NativeModules.MapplsIntouch).removeAllListeners(
      'BatteryChangeListener',
    );
    new NativeEventEmitter(NativeModules.MapplsIntouch).removeAllListeners(
      'DeviceStateChangeListener',
    );
    new NativeEventEmitter(NativeModules.MapplsIntouch).removeAllListeners(
      'GprsAvailableListener',
    );
    new NativeEventEmitter(NativeModules.MapplsIntouch).removeAllListeners(
      'GpsAvailableListener',
    );
    const eventBatteryListener = eventEmitter.addListener(
      'BatteryChangeListener',
      (event) => {
        if(props.onBatteryChange) {
          props.onBatteryChange(event)
        }
      },
    );
    const eventDeviceListener = eventEmitter.addListener(
      'DeviceStateChangeListener',
      (event) => {
        if(props.onDeviceStateChange) {
          props.onDeviceStateChange(event)
        }
      },
    );
    const eventGprsListener = eventEmitter.addListener(
      'GprsAvailableListener',
      (event) => {
        if(props.isGprsAvailable) {
          props.isGprsAvailable(event)
        }
      },
    );
    const eventGpsListener = eventEmitter.addListener(
      'GpsAvailableListener',
      (event) => {
        if(props.isGpsAvailable) {
          props.isGpsAvailable(event)
        }
      },
    );

    // var errorListener = eventEmitter.addListener(
    //   'TrackingErrorListener',
    //   (event) => {
    //     error(event);
    //   },
    // );
    return [eventBatteryListener, eventDeviceListener, eventGprsListener, eventGpsListener];
  },



  removeTrackingStateListener: () => {
    new NativeEventEmitter(NativeModules.MapplsIntouch).removeAllListeners(
      'TrackingStateListener',
    );
    new NativeEventEmitter(NativeModules.MapplsIntouch).removeAllListeners(
      'TrackingErrorListener',
    );
    new NativeEventEmitter(NativeModules.MapplsIntouch).removeAllListeners(
      'GprsAvailableListener',
    );
    new NativeEventEmitter(NativeModules.MapplsIntouch).removeAllListeners(
      'GpsAvailableListener',
    );
    NativeModules.MapplsIntouch.removeTrackingStateListener();
  },

  removeDeviceStateChangeListener: () => {
    new NativeEventEmitter(NativeModules.MapplsIntouch).removeAllListeners(
      'BatteryChangeListener',
    );
    new NativeEventEmitter(NativeModules.MapplsIntouch).removeAllListeners(
      'DeviceStateChangeListener',
    );
    // new NativeEventEmitter(NativeModules.MapplsIntouch).removeAllListeners(
    //   'DeviceStateChangeListener',
    // );
    // new NativeEventEmitter(NativeModules.MapplsIntouch).removeAllListeners(
    //   'DeviceStateChangeListener',
    // );
    NativeModules.MapplsIntouch.removeDeviceStateChangeListener();
  },

  isRunning: async function () {
    const status = await NativeModules.MapplsIntouch.isRunning();
    if (Platform.OS === 'ios') {
      return status > 0 ? true : false;
    } else {
      return status;
    }
  },
  getCurrentLocationUpdate: function (
    enableRequestPermissionIfMissing: boolean = true,
  ) {
    return NativeModules.MapplsIntouch.getCurrentLocationUpdate(
      enableRequestPermissionIfMissing,
    );
  },
  //only for ios
  initializeApisSdk: function (props: InitializeApisSdkProps) {
    // if (Platform.OS === 'ios') {
      if (
        props.clientId &&
        props.clientSecret &&
        props.mapSDKKey &&
        props.restAPIKey
      ) {
        return NativeModules.MapplsIntouchApi.initializeApisSdk(props);
      } else {
        error('Please provide IntouchApis keys.');
      }
    // }
  },
  getDevices: function (props: GetDevicesProps) {
    return NativeModules.MapplsIntouchApi.getDevices(props);
  },
  getDevice: function (props: GetDeviceProps) {
    return NativeModules.MapplsIntouchApi.getDevice(props);
  },
  getDevicesInfo: function (props: GetDeviceInfoProps) {
    return NativeModules.MapplsIntouchApi.getDevicesInfo(props);
  },
  getLocationsEvents: function (props: GetLocationEventsProps) {
    return NativeModules.MapplsIntouchApi.getLocationsEvents(props);
  },
  getDrive: function (props: GetDriveProps) {
    return NativeModules.MapplsIntouchApi.getDrive(props);
  },
  createGeoFence: function (props: CreateGeoFenceProps) {
    return NativeModules.MapplsIntouchApi.createGeoFence(props);
  },
  getGeoFences: function (props: GetGeoFencesProps) {
    return NativeModules.MapplsIntouchApi.getGeoFences(props);
  },
  updateGeoFence: function (props: UpdateGeofenceProps) {
    return NativeModules.MapplsIntouchApi.updateGeoFence(props);
  },
  deleteGeoFence: function (props: DeleteGeoFenceProps) {
    return NativeModules.MapplsIntouchApi.deleteGeoFence(props);
  },
  getGeoFenceActivity: function (props: GetGeoFenceActivity) {
    return NativeModules.MapplsIntouchApi.getGeoFenceActivity(props);
  },
  createTrip: function (props: CreateTripProps) {
    return NativeModules.MapplsIntouchApi.createTrip(props);
  },
  getTrips: function (props: GetTripsProps) {
    return NativeModules.MapplsIntouchApi.getTrips(props);
  },
  getTripInfo: function (props: GetTripInfoProps) {
    return NativeModules.MapplsIntouchApi.getTripInfo(props);
  },
  closeTrip: function (props: CloseTripProps) {
    return NativeModules.MapplsIntouchApi.closeTrip(props);
  },
  createAlarm: function (props: CreateAlarmProps) {
    return NativeModules.MapplsIntouchApi.createAlarm(props);
  },
  getAlarmConfigs: function (props: GetAlarmConfigsProps) {
    return NativeModules.MapplsIntouchApi.getAlarmConfigs(props);
  },
  updateAlarm: function (props: UpdateAlaramProps) {
    return NativeModules.MapplsIntouchApi.updateAlarm(props);
  },
  deleteAlarm: function (props: DeleteAlarmProps) {
    return NativeModules.MapplsIntouchApi.deleteAlarm(props);
  },
  getAlarmsLogs: function (props: GetAlarmLogsProps) {
    return NativeModules.MapplsIntouchApi.getAlarmsLogs(props);
  },
  BEACON_PRIORITY_FAST: BEACON_PRIORITY_FAST,
  BEACON_PRIORITY_SLOW: BEACON_PRIORITY_SLOW,
  BEACON_PRIORITY_OPTIMAL: BEACON_PRIORITY_OPTIMAL,
  BEACON_PRIORITY_DRIVING: BEACON_PRIORITY_DRIVING,

};

function error(message: string) {
  console.log(message);
  Alert.alert(message);
}

//only for ios platform
function iosSettingsAlert() {
  Alert.alert(
    'Permission',
    'Please enable location permission to use this feature',
    [{text: 'Open Settings', onPress: () => Linking.openSettings()}],
    {cancelable: true},
  );
}
export default MapplsIntouch;
