import {useCallback, useMemo} from 'react';
import Animated, {withSpring} from 'react-native-reanimated';
import {useBestIPhoneDevice} from '@modules/chats/hooks/useBestIphoneDevice';

import type {SharedValue, WithSpringConfig} from 'react-native-reanimated';

Animated.addWhitelistedUIProps({
  zoom: true,
});

const LENS_SPRING: WithSpringConfig = {
  stiffness: 600,
  damping: 60,
  mass: 1,
  overshootClamping: true,
};

export type LensInfo = {
  opticalZoom: number;
  name: string;
  rangeStart: number;
  rangeEnd: number;
  zoomFactor: number;
};

export type ActiveLensOptions = {
  lenses: LensInfo[];
  zoom: number;
  selectedLens?: string;
};

export const CameraEngine = {
  activeLens: (options: ActiveLensOptions): LensInfo | undefined => {
    const {lenses, zoom} = options;
    return (
      lenses.findLast(
        lens => lens.rangeStart !== undefined && zoom >= lens.rangeStart,
      ) ?? lenses[0]
    );
  },
  useOnLensPress: (): {
    genOnLensPress: (
      lensInfo: LensInfo,
      zoom: SharedValue<number>,
      lenses: LensInfo[],
    ) => () => void;
    selectedLens: string;
  } => {
    return {
      genOnLensPress: useCallback(
        (lensInfo: LensInfo, zoom: SharedValue<number>, lenses: LensInfo[]) => {
          const currentLensIndex = lenses.findIndex(
            l => l.zoomFactor === lensInfo.zoomFactor,
          );
          const nextIndex = (currentLensIndex + 1) % lenses.length;
          const nextLens = lenses[nextIndex];

          return () => {
            zoom.value = withSpring(nextLens.zoomFactor, LENS_SPRING);
          };
        },
        [],
      ),
      selectedLens: 'wide-angle-camera',
    };
  },
  useLenses: (minZoom: number, maxZoom: number): LensInfo[] => {
    const bestBackDevice = useBestIPhoneDevice();

    return useMemo(() => {
      const hasUltraWide = bestBackDevice?.physicalDevices.includes(
        'ultra-wide-angle-camera',
      );
      const neutralZoom = bestBackDevice?.neutralZoom ?? 1;

      const presetOpticalZooms = [
        ...(hasUltraWide ? [0.5] : []),
        1,
        2,
        ...(maxZoom / neutralZoom >= 5 ? [5] : []),
      ];

      return presetOpticalZooms.map((opticalZoom, index) => {
        const zoomFactor = opticalZoom * neutralZoom;
        const prevZoomFactor =
          index > 0 ? presetOpticalZooms[index - 1] * neutralZoom : minZoom;
        const nextZoomFactor =
          index < presetOpticalZooms.length - 1
            ? presetOpticalZooms[index + 1] * neutralZoom
            : maxZoom;

        const rangeStart =
          index === 0 ? minZoom : (prevZoomFactor + zoomFactor) / 2;
        const rangeEnd =
          index === presetOpticalZooms.length - 1
            ? maxZoom
            : (zoomFactor + nextZoomFactor) / 2;

        let name = 'wide-angle-camera';
        if (opticalZoom < 1) {
          name = 'ultra-wide-angle-camera';
        } else if (opticalZoom > 2) {
          name = 'telephoto-camera';
        }

        return {
          opticalZoom,
          name,
          rangeStart,
          rangeEnd,
          zoomFactor,
        };
      });
    }, [minZoom, maxZoom, bestBackDevice]);
  },
  useBackDevice: () => {
    const bestBackDevice = useBestIPhoneDevice();
    return bestBackDevice;
  },
};
