import React, {memo, useCallback, useEffect, useRef, useState} from 'react';
import {View} from 'react-native';
import {useTranslation} from 'react-i18next';
import Animated, {
  Easing,
  runOnJS,
  SlideInUp,
  SlideOutUp,
} from 'react-native-reanimated';
import {Gesture, GestureDetector} from 'react-native-gesture-handler';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import {StackActions} from '@react-navigation/native';
import HumandAvatar from '@assets/humandLogo.svg';
import {Typography} from '@components/_core/Typography';
import {Title} from '@components/_HuGo/Title';
import {Avatar} from '@components/_HuGo/Avatar';
import {useShadowStyles} from '@components/_HuGo/globalStyles';
import {navigationRef} from '@navigation/navigator';
import {getScreenFromNotification} from '@shared/notifications';
import {SPACING, useTheme} from '@shared/theme';
import {Screens} from '@shared/constants';

import {shiftNotification, useFirstNotification} from './store';
import {InAppNotificationBody} from './interfaces';
import {styles} from './styles';

const HIDE_DELAY = 5000;
const ENTER_DURATION = 300;
const EXIT_DURATION = 250;
// Material Design 3 "emphasized" motion — standard for transient surfaces
// like in-app notifications. Cross-platform consistent feel.
const ENTER_EASING = Easing.bezier(0.05, 0.7, 0.1, 1.0);
const EXIT_EASING = Easing.bezier(0.3, 0.0, 0.8, 0.15);

function InAppNotificationComponent() {
  const {t} = useTranslation();
  const {theme, spacing} = useTheme();
  const {top: safeTop} = useSafeAreaInsets();
  const notification = useFirstNotification();
  const [data, setData] = useState<Nullable<InAppNotificationBody>>(null);
  const lastUpdatedAt = useRef<number>(undefined);
  const hideTimerRef = useRef<Nullable<ReturnType<typeof setTimeout>>>(null);
  const shadowStyle = useShadowStyles();

  const clearHideTimer = useCallback(() => {
    if (hideTimerRef.current) {
      clearTimeout(hideTimerRef.current);
      hideTimerRef.current = null;
    }
  }, []);

  const dismiss = useCallback(() => {
    clearHideTimer();
    shiftNotification();
    lastUpdatedAt.current = undefined;
    setData(null);
  }, [clearHideTimer]);

  const scheduleHide = useCallback(() => {
    clearHideTimer();
    hideTimerRef.current = setTimeout(dismiss, HIDE_DELAY);
  }, [clearHideTimer, dismiss]);

  useEffect(() => {
    if (!notification || data) {
      return;
    }
    setData(notification);
    lastUpdatedAt.current = notification.updatedAt;
    scheduleHide();
  }, [notification, data, scheduleHide]);

  useEffect(() => {
    if (
      notification?.updatedAt &&
      notification.updatedAt !== lastUpdatedAt.current
    ) {
      lastUpdatedAt.current = notification.updatedAt;
      setData(notification);
      scheduleHide();
    }
  }, [notification?.updatedAt, notification, scheduleHide]);

  useEffect(() => clearHideTimer, [clearHideTimer]);

  const onPress = (withDismiss: boolean = true) => {
    if (withDismiss) {
      dismiss();
    }

    if (!data || !navigationRef?.isReady()) {
      return;
    }

    const nextScreen = getScreenFromNotification({
      type: data.data?.type as string,
      body: data.body,
      data: data.data,
    }) as {screen: string; params: unknown};

    if (nextScreen) {
      if (navigationRef.getCurrentRoute()?.name === Screens.CHAT_MESSAGES) {
        navigationRef.dispatch(
          StackActions.replace(nextScreen.screen, nextScreen.params as object),
        );
      } else {
        //@ts-expect-error Old implementation, we will refactor this soon
        navigationRef?.navigate(nextScreen.screen, nextScreen.params);
      }
    }
  };

  const gesture = Gesture.Exclusive(
    Gesture.Tap()
      .maxDuration(250)
      .maxDistance(10)
      .onEnd(() => {
        runOnJS(onPress)(true);
      }),
    Gesture.Pan()
      .minDistance(0)
      .activeOffsetY([-10, 10])
      .onEnd(event => {
        if (event.translationY < -50 || event.velocityY < -1000) {
          runOnJS(dismiss)();
        }
      }),
  );

  if (!data) {
    return null;
  }

  return (
    <View style={[styles.container, {top: safeTop + SPACING.x2}]}>
      <Animated.View
        entering={SlideInUp.duration(ENTER_DURATION).easing(ENTER_EASING)}
        exiting={SlideOutUp.duration(EXIT_DURATION).easing(EXIT_EASING)}>
        <GestureDetector gesture={gesture}>
          <View
            style={[
              styles.content,
              shadowStyle,
              {
                backgroundColor: theme.background.elements.default,
                borderColor: theme.border.neutral.default,
              },
            ]}>
            {data.avatar ? (
              <Avatar
                {...data.avatar}
                variant="primary"
                loaderType="skeleton"
              />
            ) : (
              <HumandAvatar width={spacing.x5} height={spacing.x5} />
            )}
            <View style={styles.centerContent}>
              <Title
                title={data.title}
                description={data.subtitle || undefined}
                size="xs"
              />
              <Typography variant="xs" numberOfLines={1}>
                {data.body}
              </Typography>
            </View>
            <Typography
              variant="xxs"
              color={theme.neutralTextDisabled}
              style={styles.date}>
              {t('time_tracker.now')}
            </Typography>
          </View>
        </GestureDetector>
      </Animated.View>
    </View>
  );
}

export const InAppNotification = memo(InAppNotificationComponent, () => true);

export {clearNotifications, pushNotification} from './store';
