import React, { useCallback, useEffect, useRef, useState } from "react";
import {
  ActivityIndicator,
  FlatList,
  Image,
  StyleSheet,
  View,
} from "react-native";
import { RouteProp } from "@react-navigation/native";
import { RootStackParamList } from "../App";
import { useApi } from "../lib/network/api";
import { useChatStore } from "../lib/stores/chats";
import { Message } from "../lib/types/discord";
import { useThemeColor } from "../lib/hooks/use-theme-color";
import { ThemedText } from "../components/themed-text";
import { ThemedView } from "../components/themed-view";
import { InputField } from "../components/ui/input-field";
import { Button } from "../components/ui/button";
import { Separator } from "../components/ui/separator";
import Attachments from "../components/chat/attachments";

const PAGE_SIZE = 50;

type ConversationRouteProp = RouteProp<RootStackParamList, "Conversation">;

export default function Conversation({ route }: { route: ConversationRouteProp }) {
  const channelId = route.params.id;
  const accentColor = useThemeColor("secondary");
  const api = useApi();

  const messages = useChatStore((s) => s.messages[channelId] ?? []);
  const noMoreOlder = useChatStore((s) => s.noMoreOlder[channelId] ?? false);
  const setNoMoreOlder = useChatStore((s) => s.setNoMoreOlder);

  const [message, setMessage] = useState("");
  const [initialLoading, setInitialLoading] = useState(!(messages.length > 1));
  const [loadingOlder, setLoadingOlder] = useState(false);
  const loadingRef = useRef(false); // used to prevent race conditions

  const getCurrentMessages = () => {
    return useChatStore.getState().messages[channelId] ?? []
  }

  const fetchInitial = useCallback(async () => {
    try {
      setInitialLoading(true);
      await api.populateMessages(channelId, { before: messages[0]?.id, limit: PAGE_SIZE });
      if (getCurrentMessages().length < PAGE_SIZE) setNoMoreOlder(channelId, true);
    } catch (err) {
      console.warn("Failed to fetch initial messages", err);
    } finally {
      setInitialLoading(false);
    }
  }, [api, channelId]);

  const fetchOlder = useCallback(async () => {
    if (loadingRef.current || loadingOlder || noMoreOlder) return;

    const current = getCurrentMessages();
    if (current.length === 0) return;

    const oldest = current[current.length - 1];
    if (!oldest?.id) return;

    try {
      loadingRef.current = true;
      setLoadingOlder(true);
      await api.populateMessages(channelId, { before: oldest.id, limit: PAGE_SIZE });

      // If server sent nothing new, no more old messages
      const updated = getCurrentMessages();
      if (
        updated.length === current.length ||
        updated.length - current.length < PAGE_SIZE
      ) {
        setNoMoreOlder(channelId, true);
      }
    } catch (err) {
      console.warn("Failed to fetch older messages", err);
    } finally {
      loadingRef.current = false;
      setLoadingOlder(false);
    }
  }, [api, channelId, loadingOlder, noMoreOlder]);

  const handleSend = useCallback(async () => {
    const msg = await api.sendMessage(channelId, message);
    if (msg.ok) setMessage("");
  }, [api, channelId, message])

  const MessageRow = React.memo(({
    message,
    prevMessage,
    isLast
  }: {
    message: Message;
    prevMessage?: Message;
    isLast: boolean;
  }) => {
    const combine =
      prevMessage?.author?.id === message.author?.id
      && !message.message_reference;

    return (
      <View
        style={[
          styles.messageContainer,
          combine ? { marginLeft: 55 } : { paddingTop: 15 },
          isLast ? { marginBottom: 8 } : null
        ]}
      >
        {!combine && (
          <Image
            style={styles.avatar}
            source={api.getAvatarUrl(message.author.id, message.author.avatar)}
          />
        )}
        <View style={{ flex: 1 }}>
          {!combine && (
            <ThemedText style={styles.messageUsername}>
              {message.author?.username ?? "Unknown"}
            </ThemedText>
          )}
          {message.content != "" && (
            <ThemedText type="default" style={styles.messageText} selectable={true}>
              {message.content}
            </ThemedText>
          )}
          <Attachments files={message.attachments} />
        </View>
      </View>
    );
  });

  const renderItem = useCallback(
    ({ item, index }: { item: Message; index: number }) => {
      const prevMessage = index < messages.length - 1 ? messages[index + 1] : undefined;
      return <MessageRow message={item} prevMessage={prevMessage} isLast={index == 0} />;
    },
    [messages]
  );

  useEffect(() => {
    if (messages.length > 1) return;
    fetchInitial();
  }, [fetchInitial]);

  return (
    <ThemedView style={{ flex: 1 }}>
      {initialLoading ? (
        <View style={styles.loadingScreen}>
          <ActivityIndicator size="large" color={accentColor as string} />
        </View>
      ) : (
        <>
          <FlatList
            data={messages}
            keyExtractor={(m: Message) => m.id}
            renderItem={renderItem}
            inverted={true}
            onEndReached={fetchOlder}
            onEndReachedThreshold={0.2}
            ListFooterComponent={loadingOlder ? <ActivityIndicator color={accentColor as string} /> : null}
            contentContainerStyle={styles.messageList}
            initialNumToRender={20}
            maxToRenderPerBatch={20}
            windowSize={5}
          />
          <Separator />
          <View style={styles.addMessage}>
            <InputField
              placeholder="Type a message..."
              style={[styles.messageInput]}
              onSubmitEditing={handleSend}
              value={message}
              onChangeText={(s) => setMessage(s)}
            />
            <Button onPress={handleSend}>
              Send
            </Button>
          </View>
        </>
      )}
    </ThemedView>
  );
}

const styles = StyleSheet.create({
  loadingScreen: {
    flex: 1,
    justifyContent: "center",
    alignItems: "center"
  },
  messageList: {
    marginLeft: 10
  },
  messageContainer: {
    display: "flex",
    flexDirection: "row",
    borderRadius: 8,
    maxWidth: "83%"
  },
  messageUsername: {
    marginTop: 2,
    fontSize: 16,
    fontWeight: "700"
  },
  messageText: {
    opacity: 0.8
  },
  avatar: {
    width: 45,
    height: 45,
    borderRadius: 1000,
    marginRight: 10
  },
  addMessage: {
    paddingVertical: 8,
    paddingHorizontal: 12,
    backgroundColor: "transparent",
    display: "flex",
    flexDirection: "row"
  },
  messageInput: {
    flex: 1,
    marginRight: 10,
    borderWidth: 0,
    paddingVertical: 5
  }
});