/**

 * Copyright (c) 2024 Huawei Technologies Co., Ltd.

 *

 * This source code is licensed under the MIT license found in the

 * LICENSE-MIT file in the root directory of this source tree.

 */



import React, { useRef } from 'react';

import {

  View,

  StyleSheet,

  Text,

  ScrollView,

  UIManager,

  findNodeHandle,

} from 'react-native';

import { TestCase, TestSuite } from '@rnoh/testerino';

import { Effect, Ref, Button } from '../components';



export function UIManagerTest() {

  return (

    <TestSuite name="UIManager.measure">

      <TestCase

        itShould="not round text measurement to integers"

        initialState={{

          view: { width: 0, height: 0 },

          text: { width: 0, height: 0 },

        }}

        arrange={({ setState }) => {

          return (

            <Ref<View>

              render={refView => {

                return (

                  <Ref<Text>

                    render={refText => {

                      return (

                        <Effect

                          onMount={() => {

                            setTimeout(() => {

                              refText.current?.measure(

                                (x, y, width, height, _left, _top) => {

                                  setState(prev => ({

                                    ...prev,

                                    text: { width, height },

                                  }));

                                },

                              );

                              refView.current?.measure(

                                (x, y, width, height, _left, _top) => {

                                  setState(prev => ({

                                    ...prev,

                                    view: { width, height },

                                  }));

                                },

                              );

                            }, 1000);

                          }}>

                          <Text

                            ref={refText}

                            style={{

                              width: 256.5,

                              height: 64.5,

                              color: '#fff',

                              borderColor: '#FF8041',

                              textAlign: 'center',

                              textAlignVertical: 'center',

                              justifyContent: 'center',

                              alignItems: 'center',

                              backgroundColor: '#7700FF',

                            }}>

                            <View

                              ref={refView}

                              style={{

                                backgroundColor: 'red',

                                width: 16.5,

                                height: 16.5,

                              }}

                            />

                            {'Measure me'}

                          </Text>

                        </Effect>

                      );

                    }}

                  />

                );

              }}

            />

          );

        }}

        assert={({ expect, state }) => {

          expect(state.view.width).to.be.closeTo(16.5, 0.4);

          expect(state.view.width).not.to.be.eq(16);

          expect(state.view.width).not.to.be.eq(17);

          expect(state.text.width).to.be.closeTo(256.5, 0.4);

          expect(state.text.width).not.to.be.eq(256);

          expect(state.text.width).not.to.be.eq(257);

          expect(state.text.height).to.be.closeTo(64.5, 0.4);

          expect(state.text.height).not.to.be.eq(65);

          expect(state.text.height).not.to.be.eq(64);

        }}

      />

      <TestCase itShould="scroll down on press">

        <DispatchCommandTest />

      </TestCase>

      <TestCase

        itShould="return view manager config"

        fn={({ expect }) => {

          expect(UIManager.getViewManagerConfig('RCTView')).to.be.an('object');

        }}

      />

      <TestCase

        itShould="not return view manager config for non-existing view"

        fn={({ expect }) => {

          expect(UIManager.getViewManagerConfig('RCTNotAView')).to.be.null;

        }}

      />

      <TestCase

        itShould="check if view manager config exists"

        fn={({ expect }) => {

          expect(UIManager.hasViewManagerConfig('RCTView')).to.be.true;

          expect(UIManager.hasViewManagerConfig('RCTNotAView')).to.be.false;

        }}

      />

      <TestCase

        itShould="measure the view with respect to the window"

        initialState={

          {} as { x: number; y: number; width: number; height: number }

        }

        arrange={({ setState }) => <MeasureInWindowTest setState={setState} />}

        assert={({ state, expect }) => {

          expect(state.width).to.be.equal(20);

          expect(state.height).to.be.equal(20);

          expect(state.x).to.be.greaterThan(10);

          expect(state.y).to.be.greaterThan(100);

        }}

      />

      <TestCase

        itShould="measure the view with respect to the parent"

        initialState={

          {} as { x: number; y: number; width: number; height: number }

        }

        arrange={({ setState }) => <MeasureLayoutTest setState={setState} />}

        assert={({ state, expect }) => {

          expect(state.width).to.be.equal(20);

          expect(state.height).to.be.equal(20);

          expect(state.x).to.be.equal(10);

          expect(state.y).to.be.equal(20);

        }}

      />

    </TestSuite>

  );

}

const MeasureLayoutTest = (props: {

  setState: React.Dispatch<

    React.SetStateAction<{ x: number; y: number; width: number; height: number }>

  >;

}) => {

  const ref = useRef<View>(null);

  const containerRef = useRef<View>(null);

  return (

    <>

      <View

        style={{

          width: 100,

          height: 100,

          backgroundColor: 'red',

          paddingLeft: 10,

          paddingTop: 20,

        }}

        ref={containerRef}>

        <View

          style={{

            width: 20,

            height: 20,

            backgroundColor: 'blue',

          }}

          ref={ref}

        />

      </View>

      <Button

        label="measureLayout"

        onPress={() => {

          if (ref.current && containerRef.current) {

            ref.current?.measureLayout(

              containerRef.current,

              (x, y, width, height) => {

                props.setState({ x: x, y: y, width: width, height: height });

              },

              () => {

                props.setState({ x: -1, y: -1, width: -1, height: -1 });

              },

            );

          }

        }}

      />

    </>

  );

};



const MeasureInWindowTest = (props: {

  setState: React.Dispatch<

    React.SetStateAction<{ x: number; y: number; width: number; height: number }>

  >;

}) => {

  const ref = useRef<View>(null);

  return (

    <>

      <View

        style={{

          width: 20,

          height: 20,

          backgroundColor: 'blue',

        }}

        ref={ref}

      />

      <Button

        label="measureInWindow"

        onPress={() => {

          ref.current?.measureInWindow((x, y, width, height) => {

            props.setState({ x: x, y: y, width: width, height: height });

          });

        }}

      />

    </>

  );

};



function DispatchCommandTest() {

  const ref = useRef<ScrollView>(null);



  return (

    <View>

      <ScrollView ref={ref} style={{ height: 100 }}>

        <View style={[styles.box, { backgroundColor: 'red' }]} />

        <View style={[styles.box, { backgroundColor: 'blue' }]} />

      </ScrollView>

      <Button

        label="scroll to bottom"

        onPress={() => {

          UIManager.dispatchViewManagerCommand(

            findNodeHandle(ref.current),

            'scrollToEnd',

            [true],

          );

        }}

      />

    </View>

  );

}



const styles = StyleSheet.create({

  container: {

    width: 100,

    height: 20,

    backgroundColor: 'red',

  },

  box: {

    height: 100,

    width: 50,

  },

  text: {

    height: 60,

  },

});