import * as React from "react";
import { FocusableGroupNative } from "@applicaster/zapp-react-native-ui-components/Components/NativeFocusables";
import { BaseFocusable } from "@applicaster/zapp-react-native-ui-components/Components/BaseFocusable";

function noop() {}

type Props = {
  id: string;
  children: (arg1: boolean) => React.ComponentType<any>;
  onWillUpdateFocus: (nativeEvent: any) => void;
  onDidUpdateFocus: (nativeEvent: any) => void;
  isFocusDisabled: boolean;
  initialItemId: string;
  resetFocusToInitialValue: boolean;
  focusGroupRef: React.Component;
  shouldUsePreferredFocus: boolean;
  groupId: string;
  preferredFocus: boolean;
  style: Record<any, any>;
  screenData: { screenId: string; parentScreenId: string };
};

export class FocusableGroup extends BaseFocusable<Props> {
  focusableGroupNativeRef: React.Component | null;
  constructor(props) {
    super(props);
    this.focusableGroupNativeRef = null;

    this.state = {
      isActive: false,
    };

    this.onWillUpdateFocus = this.onWillUpdateFocus.bind(this);
    this.onDidUpdateFocus = this.onDidUpdateFocus.bind(this);
    this.isGroup = true;

    this.shouldUsePreferredFocus = this.shouldUsePreferredFocus.bind(this);
    this.measureView = this.measureView.bind(this);
  }

  connectedScreenId() {
    const {
      screenData: { screenId, parentScreenId },
    } = this.props;

    if (screenId) {
      return null;
    }

    return parentScreenId ? `${parentScreenId}-${screenId}` : screenId;
  }

  /**
   * tells whether the group should give focus to a preferred item when it gains focus from another
   * group
   * @returns {boolean}
   */
  shouldUsePreferredFocus() {
    return this.props.shouldUsePreferredFocus || false;
  }

  /**
   * indicates whether the underlying component should claim preferred focus
   * when navigating into the group of this item
   * @returns {boolean}
   */
  isPreferredFocus() {
    return this.props.preferredFocus || false;
  }

  onWillUpdateFocus({ nativeEvent }) {
    const { isActive } = nativeEvent;
    this.setState({ isActive });
    const { onWillUpdateFocus = noop } = this.props;
    onWillUpdateFocus(nativeEvent);
  }

  onDidUpdateFocus({ nativeEvent }) {
    const { onDidUpdateFocus = noop } = this.props;
    onDidUpdateFocus(nativeEvent);
  }

  setFocusDisabled(isFocusDisabled) {
    if (this.ref) {
      this.ref.current.setNativeProps({
        isFocusDisabled,
      });
    }
  }

  render() {
    const {
      children,
      id,
      isFocusDisabled,
      initialItemId,
      resetFocusToInitialValue,
      style,
      groupId,
      ...otherProps
    } = this.props;

    const focusableStyles = style || {};

    return (
      <FocusableGroupNative
        groupId={`${groupId}`}
        itemId={id}
        ref={this.ref}
        isFocusDisabled={isFocusDisabled}
        initialItemId={initialItemId}
        resetFocusToInitialValue={resetFocusToInitialValue}
        onLayout={this.measureView}
        onViewFocus={this.onFocus}
        onViewPress={this.onPress}
        onViewBlur={this.onBlur}
        style={focusableStyles}
        {...otherProps}
        onWillUpdateFocus={this.onWillUpdateFocus}
        onDidUpdateFocus={this.onDidUpdateFocus}
      >
        {children}
      </FocusableGroupNative>
    );
  }
}
