import {
  View,
  Text,
  TextInput,
  Pressable,
  KeyboardAvoidingView,
  Platform,
  Keyboard,
} from "react-native";
import { useThemeStore } from "../../stores/ThemeStore";
import React, { useState, useRef, useEffect, useCallback } from "react";
import { useFocusEffect, router } from "expo-router";
import Header from "../../components/Header";
import BaseBackground from "../../components/BaseBackground";
import { FlashList } from "@shopify/flash-list";
import { ChatService } from "../../services";
import {
  useChatStore,
  useAuthStore,
  chatMessageToMessageData,
  MessageData,
} from "../../stores";
import { ProposedEventChange, RespondedAction } from "@calchat/shared";
import { ProposedEventCard } from "../../components/ProposedEventCard";
import { Ionicons } from "@expo/vector-icons";
import TypingIndicator from "../../components/TypingIndicator";
import { ChatBubble } from "../../components/ChatBubble";

// TODO: better shadows for everything
// (maybe with extra library because of differences between android and ios)
// TODO: max width for messages

type BubbleSide = "left" | "right";

type ChatMessageProps = {
  side: BubbleSide;
  content: string;
  proposedChanges?: ProposedEventChange[];
  onConfirm?: (proposalId: string, proposal: ProposedEventChange) => void;
  onReject?: (proposalId: string) => void;
  onEdit?: (proposalId: string, proposal: ProposedEventChange) => void;
};

type ChatInputProps = {
  onSend: (text: string) => void;
};

const TYPING_INDICATOR_DELAY_MS = 500;

const Chat = () => {
  const { isAuthenticated, isLoading: isAuthLoading } = useAuthStore();
  const {
    messages,
    addMessage,
    addMessages,
    updateMessage,
    isWaitingForResponse,
    setWaitingForResponse,
  } = useChatStore();
  const listRef =
    useRef<React.ComponentRef<typeof FlashList<MessageData>>>(null);
  const typingTimeoutRef = useRef<ReturnType<typeof setTimeout>>(undefined);
  const [currentConversationId, setCurrentConversationId] = useState<
    string | undefined
  >();
  const [hasLoadedMessages, setHasLoadedMessages] = useState(false);
  const needsInitialScroll = useRef(false);

  useEffect(() => {
    const keyboardDidShow = Keyboard.addListener("keyboardDidShow", () =>
      scrollToEnd(),
    );
    return () => keyboardDidShow.remove();
  }, []);

  // Load existing messages from database only once (on initial mount)
  // Skip on subsequent focus events to preserve local edits (e.g., edited proposals)
  useFocusEffect(
    useCallback(() => {
      if (isAuthLoading || !isAuthenticated || hasLoadedMessages) return;

      const fetchMessages = async () => {
        try {
          const conversationSummaries = await ChatService.getConversations();
          if (conversationSummaries.length > 0) {
            const conversationId = conversationSummaries[0].id;
            setCurrentConversationId(conversationId);

            const serverMessages =
              await ChatService.getConversation(conversationId);
            const clientMessages = serverMessages.map(chatMessageToMessageData);
            addMessages(clientMessages);
            needsInitialScroll.current = true;
          }
        } catch (error) {
          console.error("Failed to load messages:", error);
        } finally {
          setHasLoadedMessages(true);
        }
      };
      fetchMessages();
    }, [isAuthLoading, isAuthenticated, hasLoadedMessages]),
  );

  const scrollToEnd = (animated = true) => {
    setTimeout(() => {
      listRef.current?.scrollToEnd({ animated });
    }, 100);
  };

  const handleEventResponse = async (
    action: RespondedAction,
    messageId: string,
    conversationId: string,
    proposalId: string,
    proposedChange?: ProposedEventChange,
  ) => {
    // Mark proposal as responded (optimistic update)
    const message = messages.find((m) => m.id === messageId);
    if (message?.proposedChanges) {
      const updatedProposals = message.proposedChanges.map((p) =>
        p.id === proposalId ? { ...p, respondedAction: action } : p,
      );
      updateMessage(messageId, { proposedChanges: updatedProposals });
    }

    try {
      const response =
        action === "confirm" && proposedChange
          ? await ChatService.confirmEvent(
              conversationId,
              messageId,
              proposalId,
              proposedChange.action,
              proposedChange.event,
              proposedChange.eventId,
              proposedChange.updates,
              proposedChange.deleteMode,
              proposedChange.occurrenceDate,
            )
          : await ChatService.rejectEvent(
              conversationId,
              messageId,
              proposalId,
            );

      const botMessage: MessageData = {
        id: response.message.id,
        side: "left",
        content: response.message.content,
        conversationId: response.conversationId,
      };
      addMessage(botMessage);
      scrollToEnd();
    } catch (error) {
      console.error(`Failed to ${action} event:`, error);
      // Revert on error
      if (message?.proposedChanges) {
        const revertedProposals = message.proposedChanges.map((p) =>
          p.id === proposalId ? { ...p, respondedAction: undefined } : p,
        );
        updateMessage(messageId, { proposedChanges: revertedProposals });
      }
    }
  };

  const handleEditProposal = (
    messageId: string,
    conversationId: string,
    proposalId: string,
    proposal: ProposedEventChange,
  ) => {
    router.push({
      pathname: "/editEvent",
      params: {
        mode: "chat",
        eventData: JSON.stringify(proposal.event),
        proposalContext: JSON.stringify({
          messageId,
          proposalId,
          conversationId,
        }),
      },
    });
  };

  const handleSend = async (text: string) => {
    // Show user message immediately
    const userMessage: MessageData = {
      id: Date.now().toString(),
      side: "right",
      content: text,
      conversationId: currentConversationId,
    };
    addMessage(userMessage);
    scrollToEnd();

    // Show typing indicator after delay
    typingTimeoutRef.current = setTimeout(() => {
      setWaitingForResponse(true);
      scrollToEnd();
    }, TYPING_INDICATOR_DELAY_MS);

    try {
      // Fetch server response (include conversationId for existing conversations)
      const response = await ChatService.sendMessage({
        content: text,
        conversationId: currentConversationId,
      });

      // Track conversation ID for subsequent messages
      if (!currentConversationId) {
        setCurrentConversationId(response.conversationId);
      }

      // Show bot response
      const botMessage: MessageData = {
        id: response.message.id,
        side: "left",
        content: response.message.content,
        proposedChanges: response.message.proposedChanges,
        conversationId: response.conversationId,
      };
      addMessage(botMessage);
      scrollToEnd();
    } catch (error) {
      console.error("Failed to send message:", error);
    } finally {
      // Hide typing indicator
      clearTimeout(typingTimeoutRef.current);
      setWaitingForResponse(false);
    }
  };

  return (
    <BaseBackground>
      <ChatHeader />
      <KeyboardAvoidingView
        behavior={Platform.OS === "ios" ? "padding" : "height"}
        style={{ flex: 1 }}
      >
        <FlashList
          ref={listRef}
          data={messages}
          renderItem={({ item }) => (
            <ChatMessage
              side={item.side}
              content={item.content}
              proposedChanges={item.proposedChanges}
              onConfirm={(proposalId, proposal) =>
                handleEventResponse(
                  "confirm",
                  item.id,
                  item.conversationId!,
                  proposalId,
                  proposal,
                )
              }
              onReject={(proposalId) =>
                handleEventResponse(
                  "reject",
                  item.id,
                  item.conversationId!,
                  proposalId,
                )
              }
              onEdit={(proposalId, proposal) =>
                handleEditProposal(
                  item.id,
                  item.conversationId!,
                  proposalId,
                  proposal,
                )
              }
            />
          )}
          keyExtractor={(item) => item.id}
          keyboardDismissMode="interactive"
          keyboardShouldPersistTaps="handled"
          onContentSizeChange={() => {
            if (needsInitialScroll.current) {
              needsInitialScroll.current = false;
              listRef.current?.scrollToEnd({ animated: false });
            }
          }}
          ListFooterComponent={
            isWaitingForResponse ? <TypingIndicator /> : null
          }
        />
        <ChatInput onSend={handleSend} />
      </KeyboardAvoidingView>
    </BaseBackground>
  );
};

const ChatHeader = () => {
  const { theme } = useThemeStore();
  return (
    <Header className="flex flex-row items-center">
      <View
        className="ml-3 w-12 h-12 rounded-3xl border border-solid"
        style={{
          backgroundColor: theme.placeholderBg,
          borderColor: theme.primeFg,
        }}
      ></View>
      <Text className="text-lg pl-3" style={{ color: theme.textPrimary }}>
        CalChat
      </Text>
      <View
        className="h-2 bg-black"
        style={{
          shadowColor: theme.shadowColor,
          shadowOffset: {
            width: 0,
            height: 5,
          },
          shadowOpacity: 0.34,
          shadowRadius: 6.27,

          elevation: 10,
        }}
      />
    </Header>
  );
};

const MIN_INPUT_HEIGHT = 40;
const MAX_INPUT_HEIGHT = 150;

const ChatInput = ({ onSend }: ChatInputProps) => {
  const { theme } = useThemeStore();
  const [text, setText] = useState("");

  const handleSend = () => {
    if (text.trim()) {
      onSend(text.trim());
      setText("");
    }
  };

  return (
    <View className="flex flex-row w-full items-end my-2 px-2">
      <TextInput
        testID="chat-message-input"
        className="flex-1 border border-solid rounded-2xl px-3 py-2 mr-2"
        style={{
          backgroundColor: theme.messageBorderBg,
          color: theme.textPrimary,
          minHeight: MIN_INPUT_HEIGHT,
          maxHeight: MAX_INPUT_HEIGHT,
          textAlignVertical: "top",
        }}
        onChangeText={setText}
        value={text}
        placeholder="Nachricht..."
        placeholderTextColor={theme.textMuted}
        multiline
      />
      <Pressable testID="chat-send-button" onPress={handleSend}>
        <View
          className="w-10 h-10 rounded-full items-center justify-center"
          style={{
            backgroundColor: theme.placeholderBg,
          }}
        />
      </Pressable>
    </View>
  );
};

const ChatMessage = ({
  side,
  content,
  proposedChanges,
  onConfirm,
  onReject,
  onEdit,
}: ChatMessageProps) => {
  const { theme } = useThemeStore();
  const [currentIndex, setCurrentIndex] = useState(0);

  const hasProposals = proposedChanges && proposedChanges.length > 0;
  const hasMultiple = proposedChanges && proposedChanges.length > 1;
  const currentProposal = proposedChanges?.[currentIndex];

  const goToPrev = () => setCurrentIndex((i) => Math.max(0, i - 1));
  const goToNext = () =>
    setCurrentIndex((i) => Math.min((proposedChanges?.length || 1) - 1, i + 1));

  const canGoPrev = currentIndex > 0;
  const canGoNext = currentIndex < (proposedChanges?.length || 1) - 1;

  return (
    <ChatBubble
      side={side}
      testID={`chat-bubble-${side}`}
      style={{
        maxWidth: "80%",
        minWidth: hasProposals ? "75%" : undefined,
      }}
    >
      <Text className="p-2" style={{ color: theme.textPrimary }}>
        {content}
      </Text>

      {hasProposals && currentProposal && onConfirm && onReject && onEdit && (
        <View>
          {/* Event card with optional navigation arrows */}
          <View className="flex-row items-center">
            {/* Left arrow */}
            {hasMultiple && (
              <Pressable
                onPress={goToPrev}
                disabled={!canGoPrev}
                className="p-1"
                style={{ opacity: canGoPrev ? 1 : 0.3 }}
              >
                <Ionicons name="chevron-back" size={24} color={theme.primeFg} />
              </Pressable>
            )}

            {/* Event Card */}
            <View className="flex-1">
              <ProposedEventCard
                proposedChange={currentProposal}
                onConfirm={(proposal) => onConfirm(proposal.id, proposal)}
                onReject={() => onReject(currentProposal.id)}
                onEdit={(proposal) => onEdit(proposal.id, proposal)}
              />
            </View>

            {/* Right arrow */}
            {hasMultiple && (
              <Pressable
                onPress={goToNext}
                disabled={!canGoNext}
                className="p-1"
                style={{ opacity: canGoNext ? 1 : 0.3 }}
              >
                <Ionicons
                  name="chevron-forward"
                  size={24}
                  color={theme.primeFg}
                />
              </Pressable>
            )}
          </View>

          {/* Event counter */}
          {hasMultiple && (
            <Text
              className="text-center text-sm pb-2"
              style={{ color: theme.textSecondary || "#666" }}
            >
              Event {currentIndex + 1} von {proposedChanges.length}
            </Text>
          )}
        </View>
      )}
    </ChatBubble>
  );
};

export default Chat;
