import React, { PropsWithChildren, useRef } from 'react';
import { Animated, StyleSheet, Text, View } from 'react-native';
import { RectButton, Swipeable } from 'react-native-gesture-handler';
import { Colors } from 'src/theme';
import { getFontSize } from 'src/utils';
import { SheetManager } from 'react-native-actions-sheet';

import PinIcon from 'assets/icons/messages/pin.svg';
import ArchiveIcon from 'assets/icons/messages/archive.svg';
import DotsIcon from 'assets/icons/messages/dots.svg';
import UnpinIcon from 'assets/icons/messages/unpin.svg';
import { ChatProps } from '../types';
import { useChatStore } from 'src/stores/chatStore';
import {
  addDirtyAction,
  syncChatsIncremental
} from 'src/watermelondb/features/chat/data/chat.sync';
import { database } from 'src/watermelondb';
import { Chat } from 'src/watermelondb/models';
import { Q } from '@nozbe/watermelondb';

interface AppleStyleSwipeableRowProps extends PropsWithChildren<unknown> {
  chat: ChatProps;
  token: string;
  onRowOpen: (ref: any) => void;
}

async function findChatRecord(chat: { uid?: number | null; groupToken?: string | null }) {
  const chats = database.get<Chat>('chats');

  const query = chat.groupToken
    ? Q.where('group_chat_token', chat.groupToken)
    : Q.where('chat_uid', chat.uid ?? 0);

  const found = await chats.query(query).fetch();
  return found[0] ?? null;
}

const SwipeableRow: React.FC<AppleStyleSwipeableRowProps> = ({
  children,
  chat,
  token,
  onRowOpen
}) => {
  const swipeableRow = useRef<Swipeable>(null);
  const { setSelectedChat } = useChatStore();

  const close = () => {
    swipeableRow.current?.close();
  };

  const renderRightAction = (
    text: string,
    color: string,
    x: number,
    progress: Animated.AnimatedInterpolation<number>
  ) => {
    const trans = progress.interpolate({
      inputRange: [0, 1],
      outputRange: [x, 0]
    });

    const pressHandler = async () => {
      close();

      const updateLocal = async (key: keyof Chat, value: number) => {
        const chatRec = await findChatRecord(chat);
        if (!chatRec) return;

        await database.write(() =>
          chatRec.update((r) => {
            (r as any)[key] = value;
            addDirtyAction(r, { type: 'archive', value });
          })
        );
      };

      if (text === 'More') {
        setSelectedChat(chat);
        SheetManager.show('more-modal', {
          payload: {
            uid: chat.uid,
            groupToken: chat.groupToken,
            name: chat.name,
            avatar: chat.avatar,
            muted: chat.muted,
            token: token,
            userType: chat.userType,
            announcement: chat.announcement
          } as any
        });
      } else {
        const newArchive = chat.archive === 1 ? 0 : 1;
        await updateLocal('archive', newArchive);
        await syncChatsIncremental(token);
      }
    };

    return (
      <Animated.View style={{ flex: 1, transform: [{ translateX: trans }] }}>
        <RectButton style={[styles.rightAction, { backgroundColor: color }]} onPress={pressHandler}>
          {text === 'More' ? (
            <DotsIcon height={18} width={18} />
          ) : (
            <ArchiveIcon height={18} width={18} />
          )}
          <Text style={styles.actionText}>{text}</Text>
        </RectButton>
      </Animated.View>
    );
  };

  const renderLeftAction = (
    text: string,
    color: string,
    x: number,
    progress: Animated.AnimatedInterpolation<number>
  ) => {
    const trans = progress.interpolate({
      inputRange: [0, 1],
      outputRange: [-x, 0]
    });

    const pressHandler = async () => {
      close();

      const updateLocal = async (key: keyof Chat, value: number) => {
        const chatRec = await findChatRecord(chat);
        if (!chatRec) return;

        await database.write(() =>
          chatRec.update((r) => {
            (r as any)[key] = value;
            addDirtyAction(r, { type: 'pin', value });
          })
        );
      };
      const newPin = chat.pin === 1 ? 0 : 1;
      await updateLocal('pin', newPin);
      await syncChatsIncremental(token);
    };

    return (
      <Animated.View style={{ flex: 1, transform: [{ translateX: trans }] }}>
        <RectButton style={[styles.rightAction, { backgroundColor: color }]} onPress={pressHandler}>
          {chat.pin === 1 ? <UnpinIcon width={18} /> : <PinIcon width={18} />}
          <Text style={styles.actionText}>{text}</Text>
        </RectButton>
      </Animated.View>
    );
  };

  const renderRightActions = (progress: Animated.AnimatedInterpolation<number>) => (
    <View
      style={{
        width: 168,
        flexDirection: 'row'
      }}
    >
      {renderRightAction(
        chat.archive === 0 ? 'Archive' : 'Unarchive',
        Colors.BORDER_LIGHT,
        168,
        progress
      )}
      {renderRightAction('More', Colors.FILL_LIGHT, 112, progress)}
    </View>
  );

  const renderLeftActions = (progress: Animated.AnimatedInterpolation<number>) => (
    <View
      style={{
        width: 84,
        flexDirection: 'row'
      }}
    >
      {renderLeftAction(chat.pin === 1 ? 'Unpin' : 'Pin', Colors.FILL_LIGHT, 84, progress)}
    </View>
  );

  return (
    <Swipeable
      ref={swipeableRow}
      friction={2}
      enableTrackpadTwoFingerGesture
      rightThreshold={40}
      renderRightActions={renderRightActions}
      renderLeftActions={renderLeftActions}
      onSwipeableOpenStartDrag={() => {
        onRowOpen(swipeableRow.current);
      }}
    >
      {children}
    </Swipeable>
  );
};

const styles = StyleSheet.create({
  actionText: {
    color: Colors.DARK_BLUE,
    fontSize: getFontSize(12),
    fontWeight: '600',
    backgroundColor: 'transparent'
  },
  rightAction: {
    alignItems: 'center',
    flex: 1,
    justifyContent: 'center',
    gap: 12
  }
});

export default SwipeableRow;
