import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { Animated, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { MaterialCommunityIcons } from '@expo/vector-icons';

import { bindPromptListener, PromptPayload, PromptType } from '../../services/promptService';
import { borderRadius, shadows, spacing, useAppColors, type AppColors } from '../../theme';

interface PromptState extends PromptPayload {
  id: number;
}

const DEFAULT_DURATION = 2200;

function createPromptBarStyles(colors: AppColors) {
  return StyleSheet.create({
    wrapper: {
      position: 'absolute',
      left: spacing.md,
      right: spacing.md,
      zIndex: 9999,
    },
    card: {
      borderRadius: borderRadius.xl,
      paddingVertical: spacing.md,
      paddingHorizontal: spacing.md,
      borderWidth: 1,
      borderColor: `${colors.primary.main}22`,
      flexDirection: 'row',
      alignItems: 'center',
      overflow: 'hidden',
      ...shadows.lg,
    },
    accentBar: {
      position: 'absolute',
      left: 0,
      top: 0,
      bottom: 0,
      width: 4,
    },
    iconWrap: {
      width: 32,
      height: 32,
      borderRadius: borderRadius.full,
      backgroundColor: `${colors.primary.main}12`,
      alignItems: 'center',
      justifyContent: 'center',
      marginRight: spacing.md,
    },
    textWrap: {
      flex: 1,
      paddingRight: spacing.sm,
    },
    title: {
      color: colors.text.primary,
      fontWeight: '700',
      fontSize: 14,
      marginBottom: 2,
    },
    message: {
      color: colors.text.primary,
      fontSize: 13,
      lineHeight: 18,
    },
  });
}

const AppPromptBar: React.FC = () => {
  const insets = useSafeAreaInsets();
  const colors = useAppColors();
  const styles = useMemo(() => createPromptBarStyles(colors), [colors]);

  const styleMap = useMemo<
    Record<PromptType, { backgroundColor: string; icon: React.ComponentProps<typeof MaterialCommunityIcons>['name'] }>
  >(
    () => ({
      info: { backgroundColor: colors.background.paper, icon: 'information-outline' },
      success: { backgroundColor: colors.background.paper, icon: 'check-circle-outline' },
      warning: { backgroundColor: colors.background.paper, icon: 'alert-outline' },
      error: { backgroundColor: colors.background.paper, icon: 'alert-circle-outline' },
    }),
    [colors.background.paper],
  );

  const iconColorMap = useMemo(
    () => ({
      info: colors.primary.main,
      success: colors.success.main,
      warning: colors.warning.dark,
      error: colors.error.main,
    }),
    [colors.primary.main, colors.success.main, colors.warning.dark, colors.error.main],
  );

  const accentColorMap = useMemo(
    () => ({
      info: colors.primary.main,
      success: colors.success.main,
      warning: colors.warning.main,
      error: colors.error.main,
    }),
    [colors.primary.main, colors.success.main, colors.warning.main, colors.error.main],
  );

  const [prompt, setPrompt] = useState<PromptState | null>(null);
  const hideTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const animation = useRef(new Animated.Value(0)).current;

  const hidePrompt = useCallback(() => {
    Animated.timing(animation, {
      toValue: 0,
      duration: 180,
      useNativeDriver: true,
    }).start(({ finished }) => {
      if (finished) {
        setPrompt(null);
      }
    });
  }, [animation]);

  useEffect(() => {
    const unbind = bindPromptListener((payload) => {
      if (hideTimerRef.current) {
        clearTimeout(hideTimerRef.current);
      }

      setPrompt({
        ...payload,
        id: Date.now(),
        type: payload.type ?? 'info',
      });
    });

    return () => {
      if (hideTimerRef.current) {
        clearTimeout(hideTimerRef.current);
      }
      unbind();
    };
  }, []);

  useEffect(() => {
    if (!prompt) return;

    animation.setValue(0);
    Animated.timing(animation, {
      toValue: 1,
      duration: 220,
      useNativeDriver: true,
    }).start();

    hideTimerRef.current = setTimeout(() => {
      hidePrompt();
    }, prompt.duration ?? DEFAULT_DURATION);
  }, [animation, hidePrompt, prompt]);

  if (!prompt) return null;

  const promptType = prompt.type ?? 'info';
  const promptStyle = styleMap[promptType];
  const iconColor = iconColorMap[promptType];
  const accentColor = accentColorMap[promptType];

  return (
    <Animated.View
      pointerEvents="box-none"
      style={[
        styles.wrapper,
        {
          top: insets.top + spacing.sm,
          opacity: animation,
          transform: [
            {
              translateY: animation.interpolate({
                inputRange: [0, 1],
                outputRange: [-20, 0],
              }),
            },
          ],
        },
      ]}
    >
      <TouchableOpacity
        activeOpacity={0.95}
        onPress={hidePrompt}
        style={[styles.card, { backgroundColor: promptStyle.backgroundColor }]}
      >
        <View style={[styles.accentBar, { backgroundColor: accentColor }]} />
        <View style={styles.iconWrap}>
          <MaterialCommunityIcons name={promptStyle.icon} size={20} color={iconColor} />
        </View>
        <View style={styles.textWrap}>
          {!!prompt.title && <Text style={styles.title}>{prompt.title}</Text>}
          <Text style={styles.message}>{prompt.message}</Text>
        </View>
      </TouchableOpacity>
    </Animated.View>
  );
};

export default AppPromptBar;
