/**
 * 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,
  },
});