/* @flow */

import * as React from 'react';
import { View, ViewPagerAndroid, StyleSheet, I18nManager } from 'react-native';
import { PagerRendererPropType } from './PropTypes';
import type { PagerRendererProps } from './TypeDefinitions';

type PageScrollEvent = {
  nativeEvent: {
    position: number,
    offset: number,
  },
};

type PageScrollState = 'dragging' | 'settling' | 'idle';

type PageScrollStateEvent =
  | PageScrollState
  | {
      nativeEvent: {
        pageScrollState: PageScrollState,
      },
    };

type Props<T> = PagerRendererProps<T> & {
  keyboardDismissMode: 'none' | 'on-drag',
};

export default class PagerAndroid<T: *> extends React.Component<Props<T>> {
  static propTypes = PagerRendererPropType;

  static defaultProps = {
    canJumpToTab: () => true,
    keyboardDismissMode: 'on-drag',
  };

  constructor(props: Props<T>) {
    super(props);
    this._currentIndex = this.props.navigationState.index;
  }

  componentDidUpdate(prevProps: Props<T>) {
    if (
      prevProps.navigationState.routes.length !==
        this.props.navigationState.routes.length ||
      prevProps.layout.width !== this.props.layout.width
    ) {
      this._handlePageChange(this.props.navigationState.index, false);
    } else if (
      prevProps.navigationState.index !== this.props.navigationState.index
    ) {
      this._handlePageChange(this.props.navigationState.index);
    }
  }

  _pageChangeCallabck: any;
  _viewPager: ?ViewPagerAndroid;
  _isIdle: boolean = true;
  _currentIndex = 0;

  _getPageIndex = (index: number) =>
    I18nManager.isRTL
      ? this.props.navigationState.routes.length - (index + 1)
      : index;

  _setPage = (index: number, animated = true) => {
    const pager = this._viewPager;

    if (pager) {
      const page = this._getPageIndex(index);

      if (this.props.animationEnabled === false || animated === false) {
        pager.setPageWithoutAnimation(page);
      } else {
        pager.setPage(page);
      }
    }
  };

  _handlePageChange = (index: number, animated?: boolean) => {
    if (this._isIdle && this._currentIndex !== index) {
      this._setPage(index, animated);
      this._currentIndex = index;
    }
  };

  _handlePageScroll = (e: PageScrollEvent) => {
    this.props.offsetX.setValue(
      this._getPageIndex(e.nativeEvent.position) * this.props.layout.width * -1
    );
    this.props.panX.setValue(
      e.nativeEvent.offset *
        this.props.layout.width *
        (I18nManager.isRTL ? 1 : -1)
    );
  };

  _handlePageScrollStateChanged = (e: PageScrollStateEvent) => {
    // Support both React Native < 0.59 and 0.59+
    this._isIdle =
      typeof e !== 'string' && e.nativeEvent
        ? e.nativeEvent.pageScrollState === 'idle'
        : e === 'idle';

    let nextIndex = this._currentIndex;

    const nextRoute = this.props.navigationState.routes[nextIndex];

    if (this.props.canJumpToTab({ route: nextRoute })) {
      this.props.jumpTo(nextRoute.key);
    } else {
      this._setPage(this.props.navigationState.index);
      this._currentIndex = this.props.navigationState.index;
    }

    switch (e) {
      case 'dragging':
        this.props.onSwipeStart && this.props.onSwipeStart();
        break;
      case 'settling':
        this.props.onSwipeEnd && this.props.onSwipeEnd();
        break;
      case 'idle':
        this.props.onAnimationEnd && this.props.onAnimationEnd();
        break;
    }
  };

  _handlePageSelected = (e: PageScrollEvent) => {
    const index = this._getPageIndex(e.nativeEvent.position);
    this._currentIndex = index;
  };

  render() {
    const { navigationState, swipeEnabled, keyboardDismissMode } = this.props;
    const children = I18nManager.isRTL
      ? React.Children.toArray(this.props.children).reverse()
      : React.Children.toArray(this.props.children);

    const content = children.map((child, i) => {
      const route = navigationState.routes[i];
      const focused = i === navigationState.index;

      return (
        <View
          key={route.key}
          testID={this.props.getTestID({ route })}
          accessibilityElementsHidden={!focused}
          importantForAccessibility={focused ? 'auto' : 'no-hide-descendants'}
          style={styles.page}
        >
          {child}
        </View>
      );
    });

    const initialPage = this._getPageIndex(navigationState.index);

    return (
      <ViewPagerAndroid
        key={navigationState.routes.length}
        keyboardDismissMode={keyboardDismissMode}
        initialPage={initialPage}
        scrollEnabled={swipeEnabled !== false}
        onPageScroll={this._handlePageScroll}
        onPageScrollStateChanged={this._handlePageScrollStateChanged}
        onPageSelected={this._handlePageSelected}
        style={styles.container}
        ref={el => (this._viewPager = el)}
      >
        {content}
      </ViewPagerAndroid>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flexGrow: 1,
  },

  page: {
    overflow: 'hidden',
  },
});