/**
 * Copyright (c) 2026 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 {
  Dimensions,
  Image,
  ImageSourcePropType,
  ScrollView,
  Text,
  View,
  StyleSheet,
} from 'react-native';
import {TestSuite} from '@rnoh/testerino';
import React, {useEffect, useMemo, useState} from 'react';
import {Button, TestCase} from '../components';
import {getScrollViewContentHorizontal} from './ScrollViewTest/fixtures';
import {useEnvironment} from '../contexts';

const WRONG_IMAGE_SRC = 'not_image';
const LOCAL_IMAGE_ASSET_ID = require('../assets/pravatar-131.jpg');
const MULTI_DENSITY_IMAGE_ASSET_ID = require('../assets/fig-without-poppy.jpeg');
const REMOTE_IMAGE_URL =
  'https://images.unsplash.com/photo-1503023345310-bd7c1de61c7d?auto=format&fit=crop&w=400&q=80';
const INVALID_IMAGE_URL = '';
const BASE64_IMAGE_STRING =
  'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAFUlEQVR42mP8z8BQz0AEYBxVSF+FABJADveWkH6oAAAAAElFTkSuQmCC';
const LARGE_REMOTE_IMAGE_URL =
  'https://images.unsplash.com/photo-1556740749-887f6717d7e4';
const RANDOM_REMOTE_IMAGE_URL = 'https://picsum.photos/5000';
const REMOTE_REDIRECT_IMAGE_URL =
  'https://ix-marketing.imgix.net/bg-remove_after.png?auto=format,compress&w=1946';
const REMOTE_GIF_URL =
  'https://upload.wikimedia.org/wikipedia/commons/2/2c/Rotating_earth_%28large%29.gif';
const DATA_URI =
  'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==';
const FILE_URI = 'file:///data/storage/el2/base/files/pravatar-131.jpg';

export const ImageTest = () => {
  const {
    env: {isConnectedToInternet},
  } = useEnvironment();

  const noInternetSkipMsg = isConnectedToInternet
    ? undefined
    : 'Internet connection required';

  return (
    <TestSuite name="Image">
      <TestCase.Example itShould="support loading local images">
        <Image
          style={{borderRadius: 8, borderWidth: 1}}
          source={LOCAL_IMAGE_ASSET_ID}
        />
      </TestCase.Example>
      <ImageExampleCase
        itShould="support loading remote images"
        source={{uri: REMOTE_IMAGE_URL}}
      />
      <ImageExampleCase
        itShould="support loading remote images (with http redirect)"
        source={{uri: REMOTE_REDIRECT_IMAGE_URL}}
      />
      <ImageExampleCase
        itShould="support loading large remote images (over 5mb)"
        source={{uri: LARGE_REMOTE_IMAGE_URL}}
      />
      <ImageExampleCase
        itShould="support loading image data uris"
        source={{uri: DATA_URI}}
      />
      <ImageExampleCase
        itShould="support loading remote animated gifs"
        source={{uri: REMOTE_GIF_URL}}
      />
      <TestCase.Example itShould="display accessible image which reads 'EXAMPLE IMAGE' when focused">
        <View style={{minHeight: 50}}>
          <Image source={LOCAL_IMAGE_ASSET_ID} alt="EXAMPLE IMAGE" />
        </View>
      </TestCase.Example>
      <TestCase.Example itShould="display an image nested inside Text">
        <TextNestedImageTest />
      </TestCase.Example>
      <TestCase.Logical
        skip={{android: false, harmony: {arkTs: false, cAPI: 'NOT SUPPORTED'}}}
        itShould="retrieve remote image size"
        fn={({expect}) => {
          return new Promise((resolve, reject) => {
            Image.getSize(
              REMOTE_IMAGE_URL,
              (width, height) => {
                expect(width).to.be.eq(100);
                expect(height).to.be.eq(100);
                resolve();
              },
              e => {
                reject(e);
              },
            );
          });
        }}
      />
      <TestCase.Logical
        itShould="fail when retrieving image size for an invalid uri"
        fn={({expect}) => {
          return new Promise((resolve, reject) => {
            Image.getSize(
              INVALID_IMAGE_URL,
              () => {
                reject(
                  'retrieving the size of an image with invalid uri should fail, but it returned a success',
                );
              },
              e => {
                expect(e).to.not.be.undefined;
                resolve();
              },
            );
          });
        }}
      />
      <TestCase.Logical
        itShould="retrieve base64 image size"
        fn={({expect}) => {
          return new Promise((resolve, reject) => {
            Image.getSize(
              BASE64_IMAGE_STRING,
              (width, height) => {
                expect(width).to.be.eq(10);
                expect(height).to.be.eq(10);
                resolve();
              },
              e => {
                reject(e);
              },
            );
          });
        }}
      />
      <TestCase.Logical
        itShould="retrieve base64 image size (withHeaders)"
        fn={({expect}) => {
          return new Promise((resolve, reject) => {
            Image.getSizeWithHeaders(
              BASE64_IMAGE_STRING,
              {crossOrigin: 'use-credentials'},
              (width, height) => {
                expect(width).to.be.eq(10);
                expect(height).to.be.eq(10);
                resolve();
              },
              e => {
                reject(e);
              },
            );
          });
        }}
      />
      <TestCase.Logical
        skip={{
          android: false,
          harmony: {arkTs: false, cAPI: 'NOT SUPPORTED'},
        }}
        itShould="retrieve remote image size (with custom headers provided)"
        fn={({expect}) => {
          return new Promise((resolve, reject) => {
            Image.getSizeWithHeaders(
              REMOTE_IMAGE_URL,
              {referrerPolicy: 'no-referrer-when-downgrad'},
              (width, height) => {
                expect(width).to.be.eq(100);
                expect(height).to.be.eq(100);
                resolve();
              },
              e => {
                reject(e);
              },
            );
          });
        }}
      />
      <FileExampleCase />
      <TestCase.Logical
        itShould="retrieve local image size"
        fn={({expect}) => {
          const resolvedAsset = Image.resolveAssetSource(LOCAL_IMAGE_ASSET_ID);
          expect(resolvedAsset.width).to.be.eq(150);
          expect(resolvedAsset.height).to.be.eq(150);
        }}
      />
      <TestCase.Logical
        skip={noInternetSkipMsg}
        itShould="prefetch image"
        fn={async ({expect}) => {
          let ex: any;
          try {
            await Image.prefetch(WRONG_IMAGE_SRC);
          } catch (e) {
            ex = e;
          }
          expect(ex).to.be.not.undefined;
          expect(await Image.prefetch(REMOTE_IMAGE_URL)).to.be.true;
          expect(await Image.prefetch(REMOTE_IMAGE_URL)).to.be.true;
        }}
      />
      <TestCase.Logical
        skip={noInternetSkipMsg}
        tags={['sequential']}
        itShould="abort prefetch image"
        fn={async ({expect}) => {
          expect(
            await Image.prefetch(
              `${RANDOM_REMOTE_IMAGE_URL}?t=${new Date().getTime()}`,
              // @ts-ignore
              (requestId: number) => {
                setTimeout(() => {
                  Image.abortPrefetch?.(requestId);
                }, 50);
              },
            ),
          ).to.be.false;
        }}
      />
      <TestCase.Logical
        skip={{android: true, harmony: noInternetSkipMsg ?? false}}
        itShould="query cache"
        fn={async ({expect}) => {
          await Image.prefetch(REMOTE_IMAGE_URL);
          expect(Image.queryCache).not.to.be.undefined;
          const result = await Image.queryCache?.([
            REMOTE_IMAGE_URL,
            WRONG_IMAGE_SRC,
          ]);
          expect(result).to.be.not.undefined;
          expect(result?.[REMOTE_IMAGE_URL]).to.be.not.undefined;
          expect(result?.[REMOTE_IMAGE_URL]).to.be.eq('disk');
          expect(result?.[WRONG_IMAGE_SRC]).to.be.undefined;
        }}
      />
      <TestCase.Logical
        itShould="Automatically select high-density image variants.​"
        fn={({expect}) => {
          const resolvedAsset = Image.resolveAssetSource(
            MULTI_DENSITY_IMAGE_ASSET_ID,
          );
          const deviceScale = Dimensions.get('window').scale;
          const scales = [1, 2, 3];
          let scale = 0;
          for (let i = 0; i < scales.length; i++) {
            if (scales[i] >= deviceScale) {
              scale = scales[i];
              break;
            }
          }
          if (!scale) {
            scale = scales[scales.length - 1];
          }
          const filename = `fig-without-poppy${scale === 1 ? '' : '@' + scale + 'x'}.jpeg`;
          expect(resolvedAsset.uri).to.be.includes(filename);
        }}
      />
      <TestCase.Example
        itShould={
          'display uri prefixes for different bundle load \n-Metro:http:// \n-File:file:// \n-Resource:asset://'
        }>
        <View>
          <Text>
            Resolved Source URI:{' '}
            {Image.resolveAssetSource(require('../assets/heliport-14.svg')).uri}
          </Text>
        </View>
      </TestCase.Example>
      <TestCase.Example
        skip={{android: false, harmony: {arkTs: true, cAPI: true}}} // https://gl.swmansion.com/rnoh/react-native-harmony/-/issues/246
        itShould="render circular image on a red rectangle (overlayColor)">
        <Image
          source={LOCAL_IMAGE_ASSET_ID}
          style={{overlayColor: 'red', borderRadius: Number.MAX_SAFE_INTEGER}}
        />
      </TestCase.Example>
      <TestCase.Example itShould="Image should have 10 edge insertion area on four edges.">
        <Image
          source={LOCAL_IMAGE_ASSET_ID}
          capInsets={{top: 10, left: 10, bottom: 10, right: 10}}
        />
      </TestCase.Example>
      <TestCase.Automated
        itShould="display an image even if prefetch fails"
        skip={noInternetSkipMsg}
        initialState={{
          uri: `${REMOTE_IMAGE_URL}&t=${new Date().getTime()}`,
          wasOnErrorCalled: false,
          wasOnLoadEndCalled: false,
        }}
        arrange={({state, setState, done}) => {
          return (
            <Image
              source={{uri: state.uri}}
              style={{width: 100, height: 100}}
              onError={() => {
                setState(prev => ({...prev, wasOnErrorCalled: true}));
              }}
              onLoadEnd={() => {
                setState(prev => ({...prev, wasOnLoadEndCalled: true}));
                done();
              }}
            />
          );
        }}
        act={async ({state}) => {
          await Image.prefetch(
            state.uri,
            // @ts-ignore
            (requestId: number) => {
              setTimeout(() => {
                Image.abortPrefetch?.(requestId);
              }, 10);
            },
          );
        }}
        assert={({expect, state}) => {
          expect(state.wasOnErrorCalled).to.be.eq(false);
        }}
      />
      <TestCase.Automated
        itShould="call onLoadStart"
        initialState={'not called'}
        arrange={({state, setState, done}) => {
          return (
            <View>
              <Text>{JSON.stringify(state)}</Text>
              <Image
                source={LOCAL_IMAGE_ASSET_ID}
                onLoadStart={() => {
                  setState('called');
                  done();
                }}
              />
            </View>
          );
        }}
        act={() => {}}
        assert={({expect, state}) => {
          expect(state).to.be.eq('called');
        }}
      />

      <TestCase.Automated
        itShould="call onProgress"
        //TODO: https://gl.swmansion.com/rnoh/react-native-harmony/-/issues/1521
        skip={'broken'}
        initialState={'not called'}
        arrange={({state, setState, done}) => {
          return (
            <View>
              <Text>{JSON.stringify(state)}</Text>
              <Image
                source={LOCAL_IMAGE_ASSET_ID}
                onProgress={() => {
                  setState('called');
                  done();
                }}
              />
            </View>
          );
        }}
        act={() => {}}
        assert={({expect, state}) => {
          expect(state).to.be.eq('called');
        }}
      />
      <TestCase.Automated
        itShould="call onLoad"
        initialState={{}}
        arrange={({setState, state, done}) => {
          return (
            <View>
              <Text>{JSON.stringify(state)}</Text>
              <Image
                source={LOCAL_IMAGE_ASSET_ID}
                onLoad={event => {
                  setState(event.nativeEvent.source);
                  done();
                }}
              />
            </View>
          );
        }}
        act={() => {}}
        assert={({expect, state}) => {
          expect(state).to.contain.all.keys('width', 'height', 'uri');
        }}
      />
      <TestCase.Automated
        itShould="call onLoadEnd"
        initialState={'not called'}
        arrange={({setState, state, done}) => {
          return (
            <View>
              <Text>{JSON.stringify(state)}</Text>
              <Image
                source={LOCAL_IMAGE_ASSET_ID}
                onLoadEnd={() => {
                  setState('called');
                  done();
                }}
              />
            </View>
          );
        }}
        act={() => {}}
        assert={({expect, state}) => {
          expect(state).to.be.eq('called');
        }}
      />
      <TestCase.Automated
        itShould="call onError (local)"
        initialState={null}
        arrange={({setState, state, done}) => {
          return (
            <View>
              <Text>{JSON.stringify(state)}</Text>
              <Image
                source={require('../assets/fonts/Pacifico-Regular.ttf')}
                onError={event => {
                  setState(event.nativeEvent.error);
                  done();
                }}
              />
            </View>
          );
        }}
        act={() => {}}
        assert={({expect, state}) => {
          expect(state).to.be.not.null;
        }}
      />
      <TestCase.Automated
        itShould="call onError (remote)"
        initialState={null}
        arrange={({setState, state, done}) => {
          return (
            <View>
              <Text>{JSON.stringify(state)}</Text>
              <Image
                source={{uri: 'https://www.google.com/image'}}
                onError={event => {
                  setState(event.nativeEvent.error);
                  done();
                }}
              />
            </View>
          );
        }}
        act={() => {}}
        assert={({expect, state}) => {
          expect(state).to.be.not.null;
        }}
      />
      <TestCase.Automated
        itShould="call onLoad on prefetched image"
        skip={noInternetSkipMsg}
        initialState={{
          initialUrl: REMOTE_IMAGE_URL + '?v=' + Date.now(),
          prefetchComplete: false,
          onLoadEvent: undefined as
            | undefined
            | {
                width: number;
                height: number;
                uri: string;
              },
        }}
        arrange={({setState, state, done}) => {
          return (
            <View>
              {state.prefetchComplete &&
                (() => (
                  <>
                    <Text>{JSON.stringify(state.onLoadEvent?.uri)}</Text>
                    <Image
                      source={{uri: state.initialUrl}}
                      style={{width: 100, height: 100}}
                      onLoad={event => {
                        setState({
                          ...state,
                          onLoadEvent: event.nativeEvent.source,
                        });
                        done();
                      }}
                    />
                  </>
                ))()}
            </View>
          );
        }}
        act={async ({setState, state, done}) => {
          await Image.prefetch(state.initialUrl).then(success => {
            if (success) {
              setState({...state, prefetchComplete: true});
            } else {
              done();
            }
          });
        }}
        assert={({expect, state}) => {
          expect(state.prefetchComplete).to.be.true;
          expect(state.onLoadEvent?.uri).eq(state.initialUrl);
          expect(state.onLoadEvent?.width).eq(400);
          expect(state.onLoadEvent?.height).eq(500);
        }}
      />
      <TestSuite
        name="resizeMode" // https://gl.swmansion.com/rnoh/react-native-harmony/-/issues/245
      >
        <TestCase.Example itShould="render small image in the center (center)">
          <Image
            style={{width: '100%', height: 100}}
            source={LOCAL_IMAGE_ASSET_ID}
            resizeMode="center"
          />
        </TestCase.Example>
        <TestCase.Example itShould="render image touching top and bottom edges in the center (contain)">
          <Image
            style={{width: '100%', height: 100}}
            source={LOCAL_IMAGE_ASSET_ID}
            resizeMode="contain"
          />
        </TestCase.Example>
        <TestCase.Example itShould="fully cover test case area while preserving aspect ratio (cover)">
          <Image
            style={{width: '100%', height: 100}}
            source={LOCAL_IMAGE_ASSET_ID}
            resizeMode="cover"
          />
        </TestCase.Example>
        <TestCase.Example itShould="cover test case area by repeating image (repeat)">
          <Image
            style={{width: '100%', height: 100}}
            source={LOCAL_IMAGE_ASSET_ID}
            resizeMode="repeat"
          />
        </TestCase.Example>
        <TestCase.Example itShould="cover test case area by stretching (stretch)">
          <Image
            style={{width: '100%', height: 100}}
            source={LOCAL_IMAGE_ASSET_ID}
            resizeMode="stretch"
          />
        </TestCase.Example>
      </TestSuite>
      <TestSuite name="blurRadius">
        <TestCase.Example itShould="blur images with various blur radius">
          <View style={{flexDirection: 'row', flexWrap: 'wrap'}}>
            <Image
              style={{width: 64, height: 64, margin: 4}}
              source={LOCAL_IMAGE_ASSET_ID}
              blurRadius={0}
            />
            <Image
              style={{width: 64, height: 64, margin: 4}}
              source={LOCAL_IMAGE_ASSET_ID}
              blurRadius={5}
            />
            <Image
              style={{width: 64, height: 64, margin: 4}}
              source={LOCAL_IMAGE_ASSET_ID}
              blurRadius={10}
            />
            <Image
              style={{width: 64, height: 64, margin: 4}}
              source={LOCAL_IMAGE_ASSET_ID}
              blurRadius={15}
            />
            <Image
              style={{width: 64, height: 64, margin: 4}}
              source={LOCAL_IMAGE_ASSET_ID}
              blurRadius={20}
            />
            <Image
              style={{width: 64, height: 64, margin: 4}}
              source={LOCAL_IMAGE_ASSET_ID}
              blurRadius={25}
            />
          </View>
        </TestCase.Example>
      </TestSuite>
      <TestCase.Example itShould="replace opaque pixels with the green color (tintColor)">
        <View
          style={{
            flex: 1,
            flexDirection: 'row',
            justifyContent: 'space-around',
          }}>
          <Image
            source={require('../assets/test.png')}
            style={{
              width: 100,
              height: 100,
            }}
          />
          <Image
            source={require('../assets/test.png')}
            style={{
              width: 100,
              height: 100,
              tintColor: 'green',
            }}
          />
        </View>
      </TestCase.Example>
      <TestCase.Example modal itShould="stop displaying on press">
        <SwitchSourceTest />
      </TestCase.Example>
      <TestCase.Example itShould="render top image in a bit lower quality (difference barely visible)">
        <Image
          style={{width: 200, height: 200}}
          source={require('../assets/noise.png')}
          resizeMethod="resize"
          resizeMode="stretch"
        />
        <View style={{height: 10}} />
        <Image
          style={{width: 200, height: 200}}
          source={require('../assets/noise.png')}
          resizeMethod="scale"
          resizeMode="stretch"
        />
      </TestCase.Example>
      <TestCase.Example
        modal
        skip={{android: false, harmony: {arkTs: true, cAPI: true}}} // https://gl.swmansion.com/rnoh/react-native-harmony/-/issues/483
        itShould="fade images with varying durations">
        <View style={{flexDirection: 'row', gap: 24}}>
          <View style={{width: 100}}>
            <Image
              // HACK: ?v=Date.now() is used to prevent caching
              // - cached images are not fading/faded in
              source={{uri: REMOTE_IMAGE_URL + '?v=' + Date.now()}}
              style={{width: 100, height: 100, borderRadius: 8}}
              fadeDuration={0}
            />
            <Text>This image will fade in over the time of 0s.</Text>
          </View>
          <View style={{width: 100}}>
            <Image
              source={{uri: REMOTE_IMAGE_URL + '?v=' + Date.now()}}
              style={{width: 100, height: 100, borderRadius: 8}}
              fadeDuration={1500}
            />
            <Text>This image will fade in over the time of 1.5s.</Text>
          </View>
          <View style={{width: 100}}>
            <Image
              source={{uri: REMOTE_IMAGE_URL + '?v=' + Date.now()}}
              style={{width: 100, height: 100, borderRadius: 8}}
              fadeDuration={5000}
            />
            <Text>This image will fade in over the time of 5s.</Text>
          </View>
        </View>
        {/* To test local fadeDuration for localImages you have to disable caching */}
        <View style={{flexDirection: 'row', gap: 24}}>
          <View style={{width: 100}}>
            <Image
              source={LOCAL_IMAGE_ASSET_ID}
              style={{width: 100, height: 100, borderRadius: 8}}
              fadeDuration={0}
            />
            <Text>This image will fade in over the time of 0s.</Text>
          </View>
          <View style={{width: 100}}>
            <Image
              source={LOCAL_IMAGE_ASSET_ID}
              style={{width: 100, height: 100, borderRadius: 8}}
              fadeDuration={1500}
            />
            <Text>This image will fade in over the time of 1.5s.</Text>
          </View>
          <View style={{width: 100}}>
            <Image
              source={LOCAL_IMAGE_ASSET_ID}
              style={{width: 100, height: 100, borderRadius: 8}}
              fadeDuration={5000}
            />
            <Text>This image will fade in over the time of 5s.</Text>
          </View>
        </View>
      </TestCase.Example>
      <TestCase.Example
        modal
        itShould="load many large images without causing out-of-memory issues">
        <ScrollView>
          {Array.from({length: 25}, (_, index) => (
            <Image
              key={index}
              style={{width: 200, height: 200}}
              source={{uri: LARGE_REMOTE_IMAGE_URL}}
            />
          ))}
        </ScrollView>
      </TestCase.Example>
      <TestCase.Example itShould="allow scrolling by touching the image">
        <ImagePointerEventsTest />
      </TestCase.Example>
      <TestCase.Example
        skip={{harmony: 'currently fails (in 0.76 and 0.77)', android: false}}
        itShould="display placeholder image before loading image"
        modal>
        <Image
          style={{width: 200, height: 200}}
          source={{
            uri:
              'https://images.pexels.com/photos/33109/fall-autumn-red-season.jpg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1' +
              Date.now(),
          }}
          defaultSource={require('../assets/test.png')}
        />
      </TestCase.Example>
      <TestCase.Example
        modal
        itShould='Load images from different folders within assets directory (e.g. "assets/large-images", "assets/small-images")'>
        <LoadLocalImagesFromDifferentFolders />
      </TestCase.Example>
      <TestCase.Example
        modal
        itShould="Display custom loading indicator until image is ready to be displayed">
        <Image
          loadingIndicatorSource={require('../assets/test.png')}
          source={{
            uri:
              'https://images.pexels.com/photos/33109/fall-autumn-red-season.jpg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1' +
              +Date.now(),
          }}
          style={{width: '100%', height: 200, marginVertical: 16}}
        />
      </TestCase.Example>
      <TestCase.Example modal itShould="Prefetch large number of images">
        <ImagePrefetchTest />
      </TestCase.Example>
      <TestCase.Example
        modal
        itShould="Load proper image source for different container dimensions">
        <MultipleSourceImage />
      </TestCase.Example>
      <TestCase.Example
        modal
        itShould="render the same colors as the Android screenshot on the right">
        <ImageTintColorTest />
      </TestCase.Example>
    </TestSuite>
  );
};

const ImagePointerEventsTest = () => {
  return (
    <View style={{height: 200, justifyContent: 'center', alignItems: 'center'}}>
      <View
        pointerEvents="none"
        style={{
          position: 'absolute',
          zIndex: 1,
          height: 150,
          width: 150,
          backgroundColor: 'green',
          justifyContent: 'center',
          alignItems: 'center',
        }}>
        <Image
          source={LOCAL_IMAGE_ASSET_ID}
          style={{width: 100, height: 100}}
          resizeMode="cover"
          //@ts-ignore
          pointerEvents="none"
        />
      </View>
      <ScrollView style={{height: 200}} horizontal>
        {getScrollViewContentHorizontal({})}
      </ScrollView>
    </View>
  );
};

const ImageExampleCase = ({
  itShould,
  source,
}: {
  itShould: string;
  source: ImageSourcePropType;
}) => (
  <TestCase.Example itShould={itShould}>
    <Image
      style={{borderRadius: 8, borderWidth: 1, height: 150}}
      source={source}
      onError={e => console.error(e.nativeEvent.error, source)}
      // resizeMode="contain"
    />
  </TestCase.Example>
);

const FileExampleCase = () => {
  const [error, setError] = React.useState<string | undefined>(undefined);

  return (
    <TestCase.Example
      skip={{android: true, harmony: {arkTs: false, cAPI: false}}}
      itShould="load image from local file">
      {error !== undefined ? (
        <Text>{error}</Text>
      ) : (
        <Image
          style={{borderRadius: 8, borderWidth: 1, height: 150}}
          source={{uri: FILE_URI}}
          onError={_e =>
            setError(
              'To load the image, place it as' +
                '`/data/app/el2/100/base/com.rnoh.tester/files/pravatar-131.jpg`' +
                ' on your phone',
            )
          }
          // resizeMode="contain"
        />
      )}
    </TestCase.Example>
  );
};

const SwitchSourceTest = () => {
  const SOURCES = [
    REMOTE_IMAGE_URL,
    '',
    REMOTE_REDIRECT_IMAGE_URL,
    WRONG_IMAGE_SRC,
  ];

  const [idx, setIdx] = React.useState(0);

  return (
    <View>
      <View style={{flexDirection: 'row'}}>
        <Image source={{uri: SOURCES[idx]}} style={{width: 100, height: 100}} />
        <Text>{`Source: ${SOURCES[idx]}`}</Text>
      </View>
      <Button
        label="Switch Source"
        onPress={() => {
          setIdx(i => (i + 1) % SOURCES.length);
        }}
      />
    </View>
  );
};

const LOCAL_CODE_IMAGE_ASSET_1 = require('../assets/code-images/altumcode-dMUt0X3f59Q-unsplash.jpg');
const LOCAL_CODE_IMAGE_ASSET_2 = require('../assets/code-images/james-harrison-vpOeXr5wmR4-unsplash.jpg');

const LOCAL_DASHBOARD_IMAGE_ASSET_1 = require('../assets/dashboard-images/dashboard/luke-chesser-JKUTrJ4vK00-unsplash.jpg');
const LOCAL_DASHBOARD_IMAGE_ASSET_2 = require('../assets/dashboard-images/dashboard/stephen-dawson-qwtCeJ5cLYs-unsplash.jpg');

const LoadLocalImagesFromDifferentFolders = () => {
  return (
    <View style={{}}>
      <Text style={{marginTop: 16}}>Images from: /assets/ </Text>
      <View style={{flexDirection: 'row', flexWrap: 'wrap'}}>
        <Image
          style={{width: 100, height: 100, margin: 4, borderRadius: 8}}
          source={LOCAL_IMAGE_ASSET_ID}
        />
      </View>
      <Text style={{marginTop: 16}}>Images from: /assets/code-images/ </Text>
      <View style={{flexDirection: 'row', flexWrap: 'wrap'}}>
        <Image
          style={{width: 100, height: 100, margin: 4, borderRadius: 8}}
          source={LOCAL_CODE_IMAGE_ASSET_1}
        />
        <Image
          style={{width: 100, height: 100, margin: 4, borderRadius: 8}}
          source={LOCAL_CODE_IMAGE_ASSET_2}
        />
      </View>
      <Text style={{marginTop: 16}}>
        Images from: /assets/dashboard-images/dashboard
      </Text>
      <View style={{flexDirection: 'row', flexWrap: 'wrap'}}>
        <Image
          style={{width: 100, height: 100, margin: 4, borderRadius: 8}}
          source={LOCAL_DASHBOARD_IMAGE_ASSET_1}
        />
        <Image
          style={{width: 100, height: 100, margin: 4, borderRadius: 8}}
          source={LOCAL_DASHBOARD_IMAGE_ASSET_2}
        />
      </View>
    </View>
  );
};

const IMAGE_ID_OFFSET = new Date().getTime();
const NUMBER_OF_IMAGES = 45;

const ImagePrefetchTest = () => {
  const [renderImageList, setRenderImageList] = useState(false);

  useEffect(() => {
    // Delay the rendering of the images to allow the prefetch to start
    setTimeout(() => {
      setRenderImageList(true);
    }, 500);

    const promisesArray: Promise<boolean>[] = [];
    for (let i = 0; i < NUMBER_OF_IMAGES; i++) {
      const promise = Image.prefetch(
        REMOTE_IMAGE_URL + '&v=' + (i + IMAGE_ID_OFFSET),
      );
      promisesArray.push(promise);
    }
    Promise.all(promisesArray)
      .then(res => console.log('Successfully loaded all images', res))
      .catch(err => console.log('Failed to load all images', err));
  }, []);

  return (
    <>
      {renderImageList && (
        <ScrollView style={{height: '70%'}}>
          <Button
            label="Reload Images"
            onPress={() => {
              setRenderImageList(false);

              setTimeout(() => {
                setRenderImageList(true);
              }, 500);
            }}
          />
          <View
            style={{
              width: '100%',
              flexWrap: 'wrap',
              flexDirection: 'row',
              justifyContent: 'center',
            }}>
            {new Array(NUMBER_OF_IMAGES).fill(0).map((_, idx) => {
              return (
                <Image
                  key={idx}
                  source={{
                    uri: REMOTE_IMAGE_URL + '&v=' + (idx + IMAGE_ID_OFFSET),
                  }}
                  style={{
                    width: 60,
                    height: 60,
                    aspectRatio: 1,
                    backgroundColor: 'blue',
                  }}
                />
              );
            })}
          </View>
        </ScrollView>
      )}
    </>
  );
};

const MultipleSourceImage = () => {
  const {containerSizes, imageSources} = useMemo(() => {
    const imageContainerSizes = [
      [100, 100],
      [200, 200],
      [300, 300],
    ];
    const imageSourcesArr = [
      {
        uri: 'https://images.pexels.com/photos/5370674/pexels-photo-5370674.jpeg?cs=tinysrgb&w=100&h=100',
        width: 100,
        height: 100,
      },
      {
        uri: 'https://images.pexels.com/photos/5475178/pexels-photo-5475178.jpeg?w=200&h=200',
        width: 200,
        height: 200,
      },
      {
        uri: 'https://images.pexels.com/photos/27849695/pexels-photo-27849695/free-photo-of-a-man-riding-a-motorcycle-down-a-narrow-street.jpeg?cs=tinysrgb&w=300&h=300',
        width: 300,
        height: 300,
      },
    ];
    const pointScaleFactor = Dimensions.get('screen').scale;
    imageContainerSizes.map(el => [
      el[0] * pointScaleFactor,
      el[1] * pointScaleFactor,
    ]);
    imageSourcesArr.map(el => {
      el.width = el.width * pointScaleFactor;
      el.height = el.height * pointScaleFactor;
    });

    return {
      containerSizes: imageContainerSizes,
      imageSources: imageSourcesArr,
    };
  }, []);

  const [containerSizeIndex, setContainerSizeIndex] = useState(0);
  const [mountImageComponent, setMountImageComponent] = useState(true);

  return (
    <View>
      <Button
        label="Change container size"
        onPress={() => {
          setContainerSizeIndex(
            (containerSizeIndex + 1) % containerSizes.length,
          );
          // Make sure that component is re-mounted to apply new size
          setMountImageComponent(false);
          setTimeout(() => {
            setMountImageComponent(true);
          }, 50);
        }}
      />
      <View
        style={{
          padding: 16,
          backgroundColor: 'red',
          width: '100%',
          height: 325,
        }}>
        {mountImageComponent && (
          <Image
            source={imageSources}
            style={{
              width: containerSizes[containerSizeIndex][0],
              height: containerSizes[containerSizeIndex][1],
            }}
          />
        )}
      </View>
    </View>
  );
};

function TextNestedImageTest() {
  return (
    <View>
      <Text>
        This is an image{' '}
        <Image
          source={{uri: REMOTE_IMAGE_URL}}
          style={{height: 25, width: 25}}
        />{' '}
        nested in text.
      </Text>
    </View>
  );
}

const ImageTintColorTest = () => {
  const styles = StyleSheet.create({
    parent: {
      alignItems: 'center',
      flexDirection: 'column',
      height: '85%',
    },
    gallery: {
      flexWrap: 'wrap',
      flexDirection: 'row',
      width: '75%',
    },
    image: {
      width: '50%',
      aspectRatio: 1,
    },
    screenshot: {
      width: '100%',
      height: '50%',
      alignItems: 'center',
    },
  });

  return (
    <View style={styles.parent}>
      <View style={styles.gallery}>
        <Image
          source={require('../assets/test.png')}
          style={styles.image}
          tintColor="rgb(241, 35, 70)"
        />
        <Image
          source={require('../assets/test.png')}
          style={{tintColor: 'rgb(241, 35, 70)', ...styles.image}}
        />
        <Image
          source={require('../assets/test.png')}
          style={{opacity: 0.7, ...styles.image}}
          tintColor="rgb(241, 35, 70)"
        />
        <Image
          source={require('../assets/test.png')}
          style={{
            opacity: 0.7,
            tintColor: 'rgb(241, 35, 70)',
            ...styles.image,
          }}
        />
        <Image
          source={require('../assets/test.png')}
          style={styles.image}
          tintColor="rgba(241, 35, 70, 0.7)"
        />
        <Image
          source={require('../assets/test.png')}
          style={{
            tintColor: 'rgba(241, 35, 70, 0.7)',
            ...styles.image,
          }}
        />
      </View>
      <View style={styles.screenshot}>
        <Image
          style={{
            height: '100%',
            resizeMode: 'contain',
          }}
          source={require('../assets/android_tintColor.png')}
        />
      </View>
    </View>
  );
};