/**
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

import React, {useState} from 'react';
import {
  ActivityIndicator,
  FlatList,
  Image,
  RefreshControl,
  ScrollView,
  StyleSheet,
  Switch,
  Text,
  TextInput,
  TouchableOpacity,
  View,
} from 'react-native';

const REACT_NATIVE_LOGO_URL =
  'https://upload.wikimedia.org/wikipedia/commons/thumb/a/a7/React-icon.svg/1920px-React-icon.svg.png';

const Item = ({
  title,
  onPress,
  selected = false,
}: {
  title: string;
  onPress: () => void;
  selected?: boolean;
}) => {
  return (
    <TouchableOpacity onPress={onPress}>
      <View
        style={{
          height: 50,
          backgroundColor: selected ? 'rgb(240,240,240)' : 'lightgrey',
          borderWidth: 1,
          padding: 4,
          justifyContent: 'center',
          alignItems: 'center',
        }}>
        <Text>{title}</Text>
      </View>
    </TouchableOpacity>
  );
};

const ScrollViewItem = ({
  color,
  width,
  height,
}: {
  color: string;
  width?: number;
  height?: number;
}) => {
  return (
    <View
      style={{
        backgroundColor: color,
        width: width,
        height: height,
      }}
    />
  );
};
type PointerEventsExample = {
  component: () => React.JSX.Element;
  title: string;
};

function CounterButton() {
  const [pressCount, setPressCount] = useState(0);
  return (
    <View
      style={styles.button}
      onTouchEnd={() => setPressCount(prev => prev + 1)}>
      <Text style={styles.buttonText}>CLICK ME ({pressCount})</Text>
    </View>
  );
}

export function PointerEventsExample() {
  const [pointerEventsNone, setPointerEventsNone] = React.useState<
    'none' | undefined
  >(undefined);
  const [example, setExample] = React.useState(0);
  const [value, setValue] = React.useState(false);
  const [text, onChangeText] = React.useState('Text');
  const [isRefreshing, setIsRefreshing] = React.useState(false);
  const ref = React.useRef<ScrollView>(null);

  const onPress = (index: number) => () => {
    setExample(index);
  };

  const BoxOnlyMultiLayerNestingExample = () => {
    return (
      <View style={styles.container}>
        <Text>Clicking should not increase the counter value</Text>
        <View
          style={[
            styles.box,
            {
              backgroundColor: 'pink',
              flex: 1,
            },
          ]}
          pointerEvents="box-only"
          collapsable={false}>
          <Text>box-only</Text>
          <View
            style={[styles.button, {backgroundColor: 'lightgreen'}]}
            pointerEvents="box-none"
            collapsable={false}>
            <Text>box-none</Text>
            <CounterButton />
          </View>
        </View>
      </View>
    );
  };

  const BoxNoneMultiLayerNestingExample = () => {
    return (
      <View style={styles.container}>
        <ScrollView>
          <View
            style={[styles.box, {backgroundColor: 'lightblue', width: 300}]}
          />
        </ScrollView>
        <View
          style={[
            styles.box,
            {
              backgroundColor: 'pink',
              zIndex: 1,
              position: 'absolute',
              height: '100%',
            },
          ]}
          pointerEvents="box-none"
          collapsable={false}>
          <Text>
            Clicking should increase the counter value AND the lightblue
            ScrollView shouldn't be able to scroll when dragging over 'click me'
            rectangle
          </Text>
          <Text>box-none</Text>

          <View
            style={[styles.button, {backgroundColor: 'lightgreen'}]}
            pointerEvents="box-none"
            collapsable={false}>
            <Text>box-none</Text>
            <CounterButton />
          </View>
        </View>
      </View>
    );
  };

  const TouchableOpacityInViewExample = () => {
    return (
      <View style={styles.view} pointerEvents={pointerEventsNone}>
        <TouchableOpacity onPress={() => {}} style={{alignSelf: 'center'}}>
          <Text
            style={
              styles.text
            }>{`I am ${pointerEventsNone ? 'not ' : ''}pressable!`}</Text>
        </TouchableOpacity>
      </View>
    );
  };
  const TextInViewExample = () => {
    return (
      <View style={styles.view} pointerEvents={pointerEventsNone}>
        <Text style={styles.text}>
          {`I ${pointerEventsNone ? 'do not ' : ''}eat touches!`}
        </Text>
      </View>
    );
  };
  const ActivityIndicatorBareExample = () => {
    return (
      <ActivityIndicator
        animating
        style={{alignSelf: 'center'}}
        size={150}
        pointerEvents={pointerEventsNone}
      />
    );
  };
  const RefreshControlBareExample = () => {
    return (
      <>
        <ScrollView
          ref={ref}
          style={styles.scrollView}
          refreshControl={
            <RefreshControl
              progressViewOffset={10}
              refreshing={isRefreshing}
              onRefresh={() => {
                setIsRefreshing(true);
                setTimeout(() => setIsRefreshing(false), 1000);
              }}
              pointerEvents={pointerEventsNone}
            />
          }>
          <ScrollViewItem height={100} color="white" />
          <ScrollViewItem height={100} color="black" />
          <ScrollViewItem height={100} color="white" />
          <ScrollViewItem height={100} color="black" />
          <ScrollViewItem height={100} color="white" />
        </ScrollView>
      </>
    );
  };
  const ScrollViewInViewExample = () => {
    return (
      <View style={styles.view} pointerEvents={pointerEventsNone}>
        <ScrollView style={styles.scrollView}>
          <ScrollViewItem height={100} color="white" />
          <ScrollViewItem height={100} color="black" />
          <ScrollViewItem height={100} color="white" />
          <ScrollViewItem height={100} color="black" />
          <ScrollViewItem height={100} color="white" />
        </ScrollView>
      </View>
    );
  };
  const ScrollViewBareExample = () => {
    return (
      <>
        <ScrollView
          ref={ref}
          style={styles.scrollView}
          pointerEvents={pointerEventsNone}>
          <ScrollViewItem height={100} color="white" />
          <ScrollViewItem height={100} color="black" />
          <ScrollViewItem height={100} color="white" />
          <ScrollViewItem height={100} color="black" />
          <ScrollViewItem height={100} color="white" />
        </ScrollView>
        <Item
          title="scroll to 250"
          onPress={() => ref.current?.scrollTo({x: 0, y: 250})}
        />
      </>
    );
  };
  const ImageInViewExample = () => {
    return (
      <View style={styles.view} pointerEvents={pointerEventsNone}>
        <Image
          source={{uri: REACT_NATIVE_LOGO_URL}}
          height={100}
          resizeMode="contain"
        />
      </View>
    );
  };
  const ImageBareExample = () => {
    return (
      <Image
        source={{uri: REACT_NATIVE_LOGO_URL}}
        height={100}
        resizeMode="contain"
        // @ts-ignore
        pointerEvents={pointerEventsNone}
      />
    );
  };
  const SwitchInViewExample = () => {
    return (
      <View style={styles.view} pointerEvents={pointerEventsNone}>
        <Switch
          value={value}
          onChange={event => setValue(event.nativeEvent.value)}
        />
      </View>
    );
  };
  const SwitchBareExample = () => {
    return (
      <Switch
        value={value}
        onChange={event => setValue(event.nativeEvent.value)}
        pointerEvents={pointerEventsNone}
      />
    );
  };
  const TextInputInViewExample = () => {
    return (
      <View style={styles.view} pointerEvents={pointerEventsNone}>
        <TextInput
          style={styles.input}
          onChangeText={onChangeText}
          value={text}
        />
      </View>
    );
  };

  const TextInputBareExample = () => {
    return (
      <TextInput
        style={styles.input}
        onChangeText={onChangeText}
        value={text}
        pointerEvents={pointerEventsNone}
      />
    );
  };

  const PointerEventsExamples: PointerEventsExample[] = [
    {component: TextInputBareExample, title: 'TextInput'},
    {component: TextInputInViewExample, title: 'TextInput inside View'},
    {component: SwitchBareExample, title: 'Switch'},
    {component: SwitchInViewExample, title: 'Switch inside View'},
    {component: ImageBareExample, title: 'Image'},
    {component: ImageInViewExample, title: 'Image inside View'},
    {component: ScrollViewBareExample, title: 'ScrollView'},
    {component: ScrollViewInViewExample, title: 'ScrollView inside View'},
    {component: RefreshControlBareExample, title: 'RefreshControl'},
    {component: ActivityIndicatorBareExample, title: 'ActivityIndicator'},
    {component: TextInViewExample, title: 'Text inside View'},
    {
      component: TouchableOpacityInViewExample,
      title: 'TouchableOpacity inside View',
    },
    {
      component: BoxOnlyMultiLayerNestingExample,
      title: 'box-only multi-layer nesting',
    },
    {
      component: BoxNoneMultiLayerNestingExample,
      title: 'box-none multi-layer nesting',
    },
  ];
  return (
    <View style={styles.container}>
      <View style={styles.container80}>
        <Text style={styles.instructionsText}>
          Switching pointer events to none will allow to scroll the horizontal
          ScrollView in the background.
        </Text>
        <View>
          <FlatList
            horizontal
            data={PointerEventsExamples}
            renderItem={item => (
              <Item
                key={item.index}
                title={item.item.title}
                onPress={onPress(item.index)}
                selected={example === item.index}
              />
            )}
          />
          <ScrollView style={styles.backgroundScrollView} horizontal>
            <ScrollViewItem color="rgb(255, 230, 230)" width={300} />
            <ScrollViewItem color="rgb(230, 255, 230)" width={300} />
            <ScrollViewItem color="rgb(255, 230, 230)" width={300} />
          </ScrollView>
          <View style={styles.exampleContainer} pointerEvents="box-none">
            {PointerEventsExamples[example].component()}
          </View>
          <Item
            title={`Switch pointer events to ${pointerEventsNone ? 'default' : 'none'}`}
            onPress={() => {
              setPointerEventsNone(prev =>
                prev === undefined ? 'none' : undefined,
              );
            }}
          />
        </View>
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
  },
  container80: {
    width: '80%',
  },
  instructionsText: {
    color: 'white',
  },
  backgroundScrollView: {
    position: 'absolute',
    height: 500,
    marginTop: 50,
  },
  exampleContainer: {
    height: 500,
    borderWidth: 1,
    padding: 4,
  },
  input: {
    height: 40,
    margin: 12,
    borderWidth: 1,
    padding: 10,
  },
  view: {
    borderWidth: 1,
    padding: 20,
  },
  scrollView: {
    maxHeight: 300,
    width: '50%',
    alignSelf: 'center',
  },
  text: {
    backgroundColor: 'lightgrey',
    width: 200,
    height: 50,
    verticalAlign: 'middle',
    textAlign: 'center',
    alignSelf: 'center',
  },
  box: {
    width: 200,
    height: 1200,
    justifyContent: 'center',
    alignItems: 'center',
  },
  button: {
    marginTop: 20,
    width: 160,
    paddingLeft: 0,
    paddingRight: 0,
    paddingBottom: 80,
    paddingTop: 80,
    backgroundColor: 'lightgray',
    borderRadius: 5,
  },
  buttonText: {
    fontSize: 16,
    textAlign: 'center',
  },
});