/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow strict-local
 * @format
 */

import invariant from 'invariant';
import {Commands} from '../View/ViewNativeComponent';
import type {ColorValue} from '../../StyleSheet/StyleSheet';
import type {PressEvent} from '../../Types/CoreEventTypes';
import {Platform, View, processColor} from 'react-native';
import * as React from 'react';
import {useMemo} from 'react';

type NativeBackgroundProp = $ReadOnly<{|
  type: 'RippleAndroid',
  color: ?number,
  borderless: boolean,
  rippleRadius: ?number,
|}>;

export type RippleConfig = {|
  color?: ColorValue,
  borderless?: boolean,
  radius?: number,
|};

/**
 * Provides the event handlers and props for configuring the ripple effect on
 * supported versions of Android.
 */
export default function useAndroidRippleForView(
  rippleConfig: ?RippleConfig,
  viewRef: {|current: null | React.ElementRef<typeof View>|},
): ?$ReadOnly<{|
  onPressIn: (event: PressEvent) => void,
  onPressMove: (event: PressEvent) => void,
  onPressOut: (event: PressEvent) => void,
  viewProps: $ReadOnly<{|
    nativeBackgroundAndroid: NativeBackgroundProp,
  |}>,
|}> {
  const {color, borderless, radius} = rippleConfig ?? {};

  return useMemo(() => {
    if (
      Platform.OS === 'android' &&
      Platform.Version >= 21 &&
      (color != null || borderless != null || radius != null)
    ) {
      const processedColor = processColor(color);
      invariant(
        processedColor == null || typeof processedColor === 'number',
        'Unexpected color given for Ripple color',
      );

      return {
        viewProps: {
          // Consider supporting `nativeForegroundAndroid`
          nativeBackgroundAndroid: {
            type: 'RippleAndroid',
            color: processedColor,
            borderless: borderless === true,
            rippleRadius: radius,
          },
        },
        onPressIn(event: PressEvent): void {
          const view = viewRef.current;
          if (view != null) {
            Commands.setPressed(view, true);
            Commands.hotspotUpdate(
              view,
              event.nativeEvent.locationX ?? 0,
              event.nativeEvent.locationY ?? 0,
            );
          }
        },
        onPressMove(event: PressEvent): void {
          const view = viewRef.current;
          if (view != null) {
            Commands.hotspotUpdate(
              view,
              event.nativeEvent.locationX ?? 0,
              event.nativeEvent.locationY ?? 0,
            );
          }
        },
        onPressOut(event: PressEvent): void {
          const view = viewRef.current;
          if (view != null) {
            Commands.setPressed(view, false);
          }
        },
      };
    }
    return null;
  }, [color, borderless, radius, viewRef]);
}
