import React, { Component, createRef } from 'react';
import {
  Dimensions,
  StyleSheet,
  View,
  TouchableWithoutFeedback,
} from 'react-native';

import Option from './option';

const window = Dimensions.get('window');

interface SelectProps {
  width?: number;
  height?: number;
  optionListRef: () => any;
  onSelect?: (value: any) => void;
  onOpen?: (x: number, y: number, width: number, height: number, pageX: number, pageY: number) => void;
  defaultValue?: string;
  style?: any;
  styleOption?: any;
  styleText?: any;
  placeholder?: string;
  value?: string;
  optionListProps?: any;
  optionListExtraWidth?: number;
  optionListLeftOffset?: number;
  optionListTopOffset?: number;
  children?: React.ReactNode;
}

interface SelectState {
  defaultValue: string;
  value: string;
  placeholder: string | undefined;
}

const styles = StyleSheet.create({
  container: {
    borderColor: '#BDBDC1',
    borderWidth: 2 / window.scale,
  },
});

export default class Select extends Component<SelectProps, SelectState> {
  static defaultProps = {
    width: 200,
    height: 40,
    onSelect: () => {},
    optionListProps: {},
  };

  private pageX: number;
  private pageY: number;
  private selectRef: React.RefObject<View>;

  constructor(props: SelectProps) {
    super(props);

    this.selectRef = createRef<View>();
    this.pageX = 0;
    this.pageY = 0;

    let defaultValue = props.defaultValue || this.getDefaultValue();

    this.state = {
      defaultValue: defaultValue,
      value: props.placeholder ? props.value || '' : defaultValue,
      placeholder: props.placeholder,
    };
  }

  componentDidUpdate(prevProps: SelectProps) {
    // Replaces componentWillReceiveProps
    if (prevProps.value !== this.props.value) {
      this.setState(
        {
          value:
            this.props.value !== undefined
              ? this.props.value
              : this.props.placeholder
              ? ''
              : this.state.defaultValue,
        },
        () => this.checkChildrenProps(prevProps, this.props)
      );
    } else {
      this.checkChildrenProps(prevProps, this.props);
    }
  }

  getDefaultValue = () => {
    const { children } = this.props;
    if (Array.isArray(children)) {
      if ((children as React.ReactNode[])[0]) {
        return (children as React.ReactNode[])[0]!.props!.children;
      } else {
        return '';
      }
    } else {
      return (children as any).props.children;
    }
  };

  checkChildrenProps = (props: SelectProps, nextProps: SelectProps) => {
    if (props.children !== nextProps.children) {
      if (nextProps.children && (nextProps.children as React.ReactNode[]).length) {
        const childrenArray = React.Children.toArray(nextProps.children);
        const findValueInData =
          childrenArray &&
          childrenArray.find(
            (child: any) => child.props && child.props.children === this.state.value
          );
        if (!findValueInData) {
          this.setState({
            value: nextProps.placeholder ? '' : this.state.defaultValue,
          });
        }
      } else {
        this.setState({
          value: nextProps.placeholder ? this.state.value : this.state.defaultValue,
        });
      }
    }
  };

  reset = () => {
    const { placeholder } = this.props;
    this.setState({
      value: placeholder ? '' : this.state.defaultValue,
    });
  };

  _currentPosition = (pageX: number, pageY: number) => {
    const { height } = this.props;
    this.pageX = pageX;
    this.pageY = pageY + (height || 40);
  };

  show = () => {
    this._onPress();
  };

  /**
   * Measure the Select component's absolute position using ref.measure()
   * (Fabric-compatible replacement for UIManager.measure).
   * Then open the dropdown.
   */
  _measureAndOpen = () => {
    const measureTarget = this.selectRef.current;
    if (measureTarget && typeof measureTarget.measure === 'function') {
      let measured = false;
      // Timeout fallback: if measure callback doesn't fire (e.g. HarmonyOS Fabric),
      // fall back to stored position after 200ms
      const fallbackTimer = setTimeout(() => {
        if (!measured) {
          measured = true;
          this._openDropdown();
          if (this.props.onOpen) {
            this.props.onOpen(0, 0, 0, 0, this.pageX, this.pageY);
          }
        }
      }, 200);
      measureTarget.measure(
        (x: number, y: number, width: number, height: number, pageX: number, pageY: number) => {
          if (measured) return;
          measured = true;
          clearTimeout(fallbackTimer);
          this._currentPosition(pageX, pageY);
          this._openDropdown();
          if (this.props.onOpen) {
            this.props.onOpen(x, y, width, height, pageX, pageY);
          }
        }
      );
    } else {
      // Fallback: use stored position from last onLayout/measure
      this._openDropdown();
      if (this.props.onOpen) {
        this.props.onOpen(0, 0, 0, 0, this.pageX, this.pageY);
      }
    }
  };

  _openDropdown = () => {
    const {
      optionListRef,
      children,
      onSelect,
      width,
      height,
      optionListExtraWidth,
      optionListLeftOffset,
      optionListTopOffset,
      optionListProps,
    } = this.props;
    const { topOffset = 0, leftOffset = 0, extraWidth = 0 } = optionListProps || {};

    if (!(children && (children as React.ReactNode[]).length)) {
      return false;
    }

    if (typeof optionListRef !== 'function') {
      return false;
    }

    const optionList = optionListRef();
    if (!optionList || typeof optionList._show !== 'function') {
      return false;
    }

    const effectiveWidth = (width || 200) + extraWidth;
    const effectiveHeight = height || 40;

    optionList._show(
      children as React.ReactNode[],
      this.pageX + leftOffset,
      this.pageY + topOffset,
      effectiveWidth,
      effectiveHeight,
      (item: any, value: any = item) => {
        if (item) {
          this.setState(
            {
              value: item,
            },
            () => onSelect && onSelect(value)
          );
        } else {
          if (onSelect) {
            onSelect(null);
          }
        }
      },
      optionListProps
    );
  };

  _onPress = () => {
    this._measureAndOpen();
  };

  render() {
    const {
      width,
      height,
      style,
      styleOption,
      styleText,
      placeholder,
    } = this.props;
    const dimensions = { width, height };

    return (
      <TouchableWithoutFeedback onPress={this._onPress}>
        <View
          ref={this.selectRef}
          style={[styles.container, style, dimensions, { height: '100%' }]}>
          <Option style={styleOption} styleText={styleText}>
            {this.state.value || placeholder}
          </Option>
        </View>
      </TouchableWithoutFeedback>
    );
  }
}