import PropTypes from 'prop-types';
import React from 'react';
import { Animated, Platform, processColor, StyleSheet } from 'react-native';

import createNativeWrapper from './createNativeWrapper';
import GestureHandlerButton from './GestureHandlerButton';
import State from './State';

export const RawButton = createNativeWrapper(GestureHandlerButton, {
  shouldCancelWhenOutside: false,
  shouldActivateOnStart: false,
});

/* Buttons */

export class BaseButton extends React.Component {
  static propTypes = {
    ...RawButton.propTypes,
    onPress: PropTypes.func,
    onActiveStateChange: PropTypes.func,
  };

  constructor(props) {
    super(props);
    this._lastActive = false;
  }

  _handleEvent = ({ nativeEvent }) => {
    const { state, oldState, pointerInside } = nativeEvent;
    const active = pointerInside && state === State.ACTIVE;

    if (active !== this._lastActive && this.props.onActiveStateChange) {
      this.props.onActiveStateChange(active);
    }

    if (
      oldState === State.ACTIVE &&
      state !== State.CANCELLED &&
      this._lastActive &&
      this.props.onPress
    ) {
      this.props.onPress(active);
    }

    this._lastActive = active;
  };

  // Normally, the parent would execute it's handler first,
  // then forward the event to listeners. However, here our handler
  // is virtually only forwarding events to listeners, so we reverse the order
  // to keep the proper order of the callbacks (from "raw" ones to "processed").
  _onHandlerStateChange = e => {
    this.props.onHandlerStateChange && this.props.onHandlerStateChange(e);
    this._handleEvent(e);
  };

  _onGestureEvent = e => {
    this.props.onGestureEvent && this.props.onGestureEvent(e);
    this._handleEvent(e);
  };

  render() {
    const { style, rippleColor, ...rest } = this.props;

    return (
      <RawButton
        style={[{ overflow: 'hidden' }, style]}
        rippleColor={processColor(rippleColor)}
        {...rest}
        onGestureEvent={this._onGestureEvent}
        onHandlerStateChange={this._onHandlerStateChange}
      />
    );
  }
}

const AnimatedBaseButton = Animated.createAnimatedComponent(BaseButton);

const btnStyles = StyleSheet.create({
  underlay: {
    position: 'absolute',
    left: 0,
    right: 0,
    bottom: 0,
    top: 0,
  },
});

export class RectButton extends React.Component {
  static propTypes = BaseButton.propTypes;

  static defaultProps = {
    activeOpacity: 0.105,
    underlayColor: 'black',
  };

  constructor(props) {
    super(props);
    this._opacity = new Animated.Value(0);
  }

  _onActiveStateChange = active => {
    if (Platform.OS !== 'android') {
      this._opacity.setValue(active ? this.props.activeOpacity : 0);
    }

    this.props.onActiveStateChange && this.props.onActiveStateChange(active);
  };

  render() {
    const { children, ...rest } = this.props;

    return (
      <BaseButton {...rest} onActiveStateChange={this._onActiveStateChange}>
        <Animated.View
          style={[
            btnStyles.underlay,
            { opacity: this._opacity },
            { backgroundColor: this.props.underlayColor },
          ]}
        />
        {children}
      </BaseButton>
    );
  }
}

export class BorderlessButton extends React.Component {
  static propTypes = {
    ...BaseButton.propTypes,
    borderless: PropTypes.bool,
  };

  static defaultProps = {
    activeOpacity: 0.3,
    borderless: true,
  };

  constructor(props) {
    super(props);
    this._opacity = new Animated.Value(1);
  }

  _onActiveStateChange = active => {
    if (Platform.OS !== 'android') {
      this._opacity.setValue(active ? this.props.activeOpacity : 1);
    }

    this.props.onActiveStateChange && this.props.onActiveStateChange(active);
  };

  render() {
    const { children, style, ...rest } = this.props;

    return (
      <AnimatedBaseButton
        {...rest}
        onActiveStateChange={this._onActiveStateChange}
        style={[style, Platform.OS === 'ios' && { opacity: this._opacity }]}>
        {children}
      </AnimatedBaseButton>
    );
  }
}

export { default as PureNativeButton } from './GestureHandlerButton';

@@ -1765,23 +1765,16 @@
  const %7B
- style,
  rippleC
@@ -1838,56 +1838,8 @@
 ton%0A
-        style=%7B%5B%7B overflow: 'hidden' %7D, style%5D%7D%0A
     
@@ -2780,16 +2780,23 @@
 hildren,
+ style,
  ...rest
@@ -2805,32 +2805,92 @@
  = this.props;%0A%0A
+    const resolvedStyle = StyleSheet.flatten(style ?? %7B%7D);%0A%0A
     return (%0A   
@@ -3050,16 +3050,30 @@
        %7B
+%0A             
  opacity
@@ -3087,18 +3087,16 @@
 _opacity
- %7D
 ,%0A      
@@ -3101,17 +3101,17 @@
         
-%7B
+ 
  backgro
@@ -3144,16 +3144,381 @@
 layColor
+,%0A              borderRadius: resolvedStyle.borderRadius,%0A              borderTopLeftRadius: resolvedStyle.borderTopLeftRadius,%0A              borderTopRightRadius: resolvedStyle.borderTopRightRadius,%0A              borderBottomLeftRadius: resolvedStyle.borderBottomLeftRadius,%0A              borderBottomRightRadius: resolvedStyle.borderBottomRightRadius,%0A           
  %7D,%0A    

Remove overflow: hidden from BaseButton to fix shadows on iOS (#974)