import React, {useCallback, useEffect, useRef, useState} from 'react';
import {View, TextInput, StyleProp, ViewStyle} from 'react-native';
import {
  IconMicrophone,
  IconMicrophoneFilled,
  IconPlayerPause,
  IconPlayerPlay,
  IconPlayerPlayFilled,
} from '@tabler/icons-react-native';
import {Pressable as GHPressable} from 'react-native-gesture-handler';
import {
  Avatar,
  AvatarProps,
  IconButton,
  RNGesturePressableNoDoubleTap,
  Spinner,
  Typography,
} from '@components';
import {SPACING, useTheme} from '@shared/theme';
import {formatSecondsToTime} from '@shared/utils';

import {styles} from './styles';
import {AudioTimeline} from '../AudioTimeline';

const TOGGLE_RATE_BTN_HIT_SLOP = {top: 10, bottom: 10, left: 10, right: 10};

interface Props {
  isPlaying: boolean;
  isPaused?: boolean;
  isLoading?: boolean;
  rate: number;
  duration: number;
  progress: number;
  avatar?: AvatarProps;
  onToggleRate: () => void;
  onPause: () => void;
  onPlay: () => void;
  onSeek: (progress: number) => void;
  rowReverse?: boolean;
  children?: React.ReactNode;
  containerStyle?: StyleProp<ViewStyle>;
  /** `bubble` = chat-style fixed width; `fill` = full width of parent (e.g. feed PostAudioCard). */
  layout?: 'bubble' | 'fill';
  /** Extra horizontal padding on the timeline track (default 0). Feed-only. */
  timelineHorizontalInset?: number;
  /**
   * When `false`, renders the feed layout (no leading avatar/rate column,
   * rate chip in footer). When `true` (default), renders the original chat
   * layout — kept byte-for-byte equivalent to the pre-feed shape so the
   * chats team's callsites don't shift.
   */
  showLeadingAvatar?: boolean;
}

export function AudioPlayer({
  isPlaying,
  isPaused,
  onToggleRate,
  rate,
  isLoading,
  onPause,
  onPlay,
  duration,
  progress,
  onSeek,
  rowReverse = false,
  avatar,
  children,
  containerStyle,
  layout = 'bubble',
  timelineHorizontalInset = 0,
  showLeadingAvatar = true,
}: Props) {
  const {theme} = useTheme();
  const timeRef = useRef<TextInput>(null);
  const isDraggingRef = useRef(false);
  const [isPlayed, setIsPlayed] = useState(false);

  const updateTime = (value: number) => {
    timeRef.current?.setNativeProps({
      text: formatSecondsToTime(Math.round(value), {
        minutesFormat: 'm',
      }),
    });
  };

  const onDragging = useCallback(() => {
    isDraggingRef.current = true;
  }, []);

  const onDraggingEnd = useCallback(() => {
    isDraggingRef.current = false;
    if (!isPlaying) {
      updateTime(duration);
    }
  }, [duration, isPlaying]);

  const onChangeProgress = useCallback(
    (position: number) => {
      updateTime(Math.round(position));
      onSeek(position);
    },
    [onSeek],
  );

  useEffect(() => {
    if (!isDraggingRef.current) {
      updateTime(isPlaying ? duration * progress : duration);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [isPlaying, progress]);

  // Mark as played once, to change the style
  useEffect(() => {
    if (isPlaying) {
      setIsPlayed(true);
    }
  }, [isPlaying]);

  const reversedColor =
    rowReverse && !isPlayed ? theme.icon.neutral.lighter : theme.brand[500];

  if (!showLeadingAvatar) {
    return (
      <View
        style={[
          layout === 'fill' ? styles.rowFill : styles.row,
          containerStyle,
        ]}>
        <View style={styles.playerRowFill}>
          <View style={styles.playControlSlot}>
            {isLoading ? (
              <Spinner />
            ) : (
              <RNGesturePressableNoDoubleTap>
                <IconButton
                  variant="flat"
                  size="sm"
                  iconColor={theme.text.neutral.default}
                  style={[styles.iconButton, styles.playIconPressable]}
                  hitSlop={SPACING.x1}
                  Icon={isPlaying ? IconPlayerPause : IconPlayerPlay}
                  onPress={isPlaying ? onPause : onPlay}
                  useGestureHandler
                />
              </RNGesturePressableNoDoubleTap>
            )}
          </View>
          <View
            style={[
              styles.timelineTrack,
              {paddingHorizontal: timelineHorizontalInset},
            ]}>
            <AudioTimeline
              duration={duration}
              progress={progress}
              onChangeProgress={onChangeProgress}
              onDragging={onDragging}
              onDraggingEnd={onDraggingEnd}
            />
          </View>
        </View>
        <View style={styles.footerFill}>
          <View style={styles.footerStart}>
            {/* TextInput is used to be able to set the value using setNativeProps (without re-rendering) */}
            <TextInput
              ref={timeRef}
              editable={false}
              style={[styles.timeInput, {color: theme.text.neutral.lighter}]}
              allowFontScaling={false}
              textAlignVertical="bottom"
            />
            {children}
          </View>
          {isPlaying || isPaused ? (
            <RNGesturePressableNoDoubleTap>
              <GHPressable
                hitSlop={TOGGLE_RATE_BTN_HIT_SLOP}
                onPress={onToggleRate}
                style={[
                  styles.changeRateButton,
                  styles.footerRateChip,
                  {backgroundColor: theme.brand[500]},
                ]}>
                <Typography variant="xxs" color={theme.text.neutral.inverted}>
                  {`${rate}x`}
                </Typography>
              </GHPressable>
            </RNGesturePressableNoDoubleTap>
          ) : null}
        </View>
      </View>
    );
  }

  return (
    <View
      style={[layout === 'fill' ? styles.rowFill : styles.row, containerStyle]}>
      <View style={[styles.container, rowReverse && styles.alignRight]}>
        <View style={styles.avatarWithRateWrapper}>
          {isPlaying || isPaused ? (
            <RNGesturePressableNoDoubleTap>
              <GHPressable
                hitSlop={TOGGLE_RATE_BTN_HIT_SLOP}
                onPress={onToggleRate}
                style={[
                  styles.changeRateButton,
                  {backgroundColor: theme.brand[500]},
                ]}>
                <Typography
                  variant="xxs"
                  weight="semiBold"
                  color={theme.text.neutral.inverted}>
                  {`${rate}x`}
                </Typography>
              </GHPressable>
            </RNGesturePressableNoDoubleTap>
          ) : avatar ? (
            <View>
              <Avatar size="md" {...avatar} />
              <IconMicrophoneFilled
                color={reversedColor}
                size={SPACING.x2}
                style={rowReverse ? styles.micIconReversed : styles.micIcon}
              />
            </View>
          ) : (
            <Avatar size="md" Icon={IconMicrophone} variant="success" />
          )}
        </View>
        <View style={styles.playerWithFooterWrapper}>
          <View style={styles.playerRow}>
            {isLoading ? (
              <Spinner />
            ) : (
              <RNGesturePressableNoDoubleTap>
                <IconButton
                  variant={'flat'}
                  size={'lg'}
                  iconColor={theme.icon.neutral.lighter}
                  hitSlop={SPACING.x1}
                  Icon={isPlaying ? IconPlayerPause : IconPlayerPlayFilled}
                  onPress={isPlaying ? onPause : onPlay}
                  useGestureHandler
                />
              </RNGesturePressableNoDoubleTap>
            )}
            <AudioTimeline
              duration={duration}
              progress={progress}
              onChangeProgress={onChangeProgress}
              onDragging={onDragging}
              onDraggingEnd={onDraggingEnd}
              thumbColor={reversedColor}
            />
          </View>
          <View style={[styles.footer, rowReverse && styles.footerReversed]}>
            {/* TextInput is used to be able to set the value using setNativeProps (without re-rendering) */}
            <TextInput
              ref={timeRef}
              editable={false}
              style={[styles.timeInput, {color: theme.text.neutral.lighter}]}
              allowFontScaling={false}
              textAlignVertical="bottom"
            />
            {children}
          </View>
        </View>
      </View>
    </View>
  );
}
