import { Box, IconButton, InputAdornment, TextField, Typography, useMediaQuery, useTheme } from "@mui/material";
import { addOrUpdateMessages, clearMessageState, incrementMessageApiPage, setIsPreventAutoscroll, setTicketMessagesFetchState, useMessageStore } from "@root/stores/messages";
import Message from "./Message";
import SendIcon from "@mui/icons-material/Send";
import AttachFileIcon from "@mui/icons-material/AttachFile";
import { KeyboardEvent, useEffect, useMemo, useRef, useState } from "react";
import { useParams } from "react-router-dom";
import { TicketMessage } from "@root/model/ticket";
import { sendTicketMessage } from "@root/api/tickets";
import { enqueueSnackbar } from "notistack";
import { useTicketStore } from "@root/stores/tickets";
import { getMessageFromFetchError, throttle, useEventListener, useSSESubscription, useTicketMessages, useToken } from "@frontend/kitui";
import makeRequest from "@root/api/makeRequest";
import ChatImage from "./ChatImage";
import ChatDocument from "./ChatDocument";
import ChatVideo from "./ChatVideo";
import ChatMessage from "./ChatMessage";
import { ACCEPT_SEND_MEDIA_TYPES_MAP, MAX_FILE_SIZE, MAX_PHOTO_SIZE, MAX_VIDEO_SIZE } from "./fileUpload";

const tooLarge = "Файл слишком большой"
const checkAcceptableMediaType = (file: File) => {
    if (file === null) return ""
  
    const segments = file?.name.split('.');
    const extension = segments[segments.length - 1];
    const type = extension.toLowerCase();
  
    switch (type) {
      case ACCEPT_SEND_MEDIA_TYPES_MAP.document.find(name => name === type):
        if (file.size > MAX_FILE_SIZE) return tooLarge
        return ""
  
      case ACCEPT_SEND_MEDIA_TYPES_MAP.picture.find(name => name === type):
        if (file.size > MAX_PHOTO_SIZE) return tooLarge
        return ""
  
      case ACCEPT_SEND_MEDIA_TYPES_MAP.video.find(name => name === type):
        if (file.size > MAX_VIDEO_SIZE) return tooLarge
        return ""
  
      default:
        return "Не удалось отправить файл. Недопустимый тип"
    }
  }

export default function Chat() {
    const token = useToken();
    const theme = useTheme();
    const upMd = useMediaQuery(theme.breakpoints.up("md"));
    const tickets = useTicketStore(state => state.tickets);
    const messages = useMessageStore(state => state.messages);
    const [messageField, setMessageField] = useState<string>("");
    const ticketId = useParams().ticketId;
    const chatBoxRef = useRef<HTMLDivElement>(null);
    const messageApiPage = useMessageStore(state => state.apiPage);
    const messagesPerPage = useMessageStore(state => state.messagesPerPage);
    const isPreventAutoscroll = useMessageStore(state => state.isPreventAutoscroll);
    const fetchState = useMessageStore(state => state.ticketMessagesFetchState);
    const lastMessageId = useMessageStore(state => state.lastMessageId);
    const fileInputRef = useRef<HTMLInputElement>(null);
    const [disableFileButton, setDisableFileButton] = useState(false);

    const ticket = tickets.find(ticket => ticket.id === ticketId);

    useTicketMessages({
        url: process.env.REACT_APP_DOMAIN + "/heruvym/getMessages",
        ticketId,
        messagesPerPage,
        messageApiPage,
        onSuccess: messages => {
            if (chatBoxRef.current && chatBoxRef.current.scrollTop < 1) chatBoxRef.current.scrollTop = 1;
            addOrUpdateMessages(messages);
        },
        onError: (error: Error) => {
            const message = getMessageFromFetchError(error);
            if (message) enqueueSnackbar(message);
        },
        onFetchStateChange: setTicketMessagesFetchState,
    });

    useSSESubscription<TicketMessage>({
        enabled: Boolean(token) && Boolean(ticketId),
        url: process.env.REACT_APP_DOMAIN + `/heruvym/ticket?ticket=${ticketId}&Authorization=${token}`,
        onNewData: addOrUpdateMessages,
        onDisconnect: () => {
            clearMessageState();
            setIsPreventAutoscroll(false);
        },
        marker: "ticket message"
    });

    const throttledScrollHandler = useMemo(() => throttle(() => {
        const chatBox = chatBoxRef.current;
        if (!chatBox) return;

        const scrollBottom = chatBox.scrollHeight - chatBox.scrollTop - chatBox.clientHeight;
        const isPreventAutoscroll = scrollBottom > chatBox.clientHeight * 20;
        setIsPreventAutoscroll(isPreventAutoscroll);

        if (fetchState !== "idle") return;

        if (chatBox.scrollTop < chatBox.clientHeight) {
            incrementMessageApiPage();
        }
    }, 200), [fetchState]);

    useEventListener("scroll", throttledScrollHandler, chatBoxRef);

    useEffect(function scrollOnNewMessage() {
        if (!chatBoxRef.current) return;

        if (!isPreventAutoscroll) {
            setTimeout(() => {
                scrollToBottom();
            }, 50);
        }
        // eslint-disable-next-line react-hooks/exhaustive-deps
    }, [lastMessageId]);

    function scrollToBottom(behavior?: ScrollBehavior) {
        if (!chatBoxRef.current) return;

        const chatBox = chatBoxRef.current;
        chatBox.scroll({
            left: 0,
            top: chatBox.scrollHeight,
            behavior,
        });
    }

    function handleSendMessage() {
        if (!ticket || !messageField) return;

        sendTicketMessage({
            files: [],
            lang: "ru",
            message: messageField,
            ticket: ticket.id,
        });
        setMessageField("");
    }

    const sendFile = async (file: File) => {
        if (file === undefined) return true;
    
        let data;
    
        const ticketId = ticket?.id
        if (ticketId !== undefined) {
          try {
            const body = new FormData();
    
            body.append(file.name, file);
            body.append("ticket", ticketId);
            await makeRequest({
              url: process.env.REACT_APP_DOMAIN + "/heruvym/sendFiles",
              body: body,
              method: "POST",
            });
          } catch (error: any) {
            const errorMessage = getMessageFromFetchError(error);
            if (errorMessage) enqueueSnackbar(errorMessage);
          }
          return true;
        }
      };
    const sendFileHC = async (file: File) => {
        const check = checkAcceptableMediaType(file)
        if (check.length > 0) {
          enqueueSnackbar(check)
          return
        }
        setDisableFileButton(true)
        await sendFile(file)
        setDisableFileButton(false)
      };

    function handleTextfieldKeyPress(e: KeyboardEvent) {
        if (e.key === "Enter" && !e.shiftKey) {
            e.preventDefault();
            handleSendMessage();
        }
    }

    return (
        <Box sx={{
            border: "1px solid",
            borderColor: theme.palette.grayDark.main,
            height: "600px",
            borderRadius: "3px",
            p: "8px",
            display: "flex",
            flex: upMd ? "2 0 0" : undefined,
            flexDirection: "column",
            justifyContent: "center",
            alignItems: "center",
            gap: "8px",
        }}>
            <Typography>{ticket ? ticket.title : "Выберите тикет"}</Typography>
            <Box
                ref={chatBoxRef}
                sx={{
                    width: "100%",
                    backgroundColor: "#46474a",
                    flexGrow: 1,
                    display: "flex",
                    flexDirection: "column",
                    gap: "12px",
                    p: "8px",
                    overflow: "auto",
                    colorScheme: "dark",
                }}
            >
                {ticket &&
                    messages.map((message) => {
                        const isFileVideo = () => {
                            if (message.files) {
                                return (ACCEPT_SEND_MEDIA_TYPES_MAP.video.some((fileType) =>
                                    message.files[0].toLowerCase().endsWith(fileType),
                                ))
                            }
                        };
                        const isFileImage = () => {
                            if (message.files) {
                                return (ACCEPT_SEND_MEDIA_TYPES_MAP.picture.some((fileType) =>
                                    message.files[0].toLowerCase().endsWith(fileType),
                                ))
                            }
                        };
                        const isFileDocument = () => {
                            if (message.files) {
                                return (ACCEPT_SEND_MEDIA_TYPES_MAP.document.some((fileType) =>
                                    message.files[0].toLowerCase().endsWith(fileType),
                                ))
                            }
                        };
                        if (message.files !== null && message.files.length > 0 && isFileImage()) {
                            return <ChatImage
                                unAuthenticated
                                key={message.id}
                                file={message.files[0]}
                                createdAt={message.created_at}
                                isSelf={ticket.user !== message.user_id}
                            />
                        }
                        if (message.files !== null && message.files.length > 0 && isFileVideo()) {
                            return <ChatVideo
                                unAuthenticated
                                key={message.id}
                                file={message.files[0]}
                                createdAt={message.created_at}
                                isSelf={ticket.user !== message.user_id}
                            />
                        }
                        if (message.files !== null && message.files.length > 0 && isFileDocument()) {
                            return <ChatDocument
                                unAuthenticated
                                key={message.id}
                                file={message.files[0]}
                                createdAt={message.created_at}
                                isSelf={ticket.user !== message.user_id}
                            />
                        }
                        return <ChatMessage
                            unAuthenticated
                            key={message.id}
                            text={message.message}
                            createdAt={message.created_at}
                            isSelf={ticket.user !== message.user_id}
                        />

                    })
                }
            </Box>
            {ticket &&
                <TextField
                    value={messageField}
                    onChange={e => setMessageField(e.target.value)}
                    onKeyPress={handleTextfieldKeyPress}
                    id="message-input"
                    placeholder="Написать сообщение"
                    fullWidth
                    multiline
                    maxRows={8}
                    InputProps={{
                        style: {
                            backgroundColor: theme.palette.content.main,
                            color: theme.palette.secondary.main,
                        },
                        endAdornment: (
                            <InputAdornment position="end">
                                <IconButton
                                    onClick={handleSendMessage}
                                    sx={{
                                        height: "45px",
                                        width: "45px",
                                        p: 0,
                                    }}
                                >
                                    <SendIcon sx={{ color: theme.palette.golden.main }} />
                                </IconButton>
                                <IconButton
                                    onClick={() => {
                                        if (!disableFileButton) fileInputRef.current?.click()
                                    }}
                                    sx={{
                                        height: "45px",
                                        width: "45px",
                                        p: 0,
                                    }}
                                >
                                    <input
                                        ref={fileInputRef}
                                        id="fileinput"
                                        onChange={(e) => {
                                            if (e.target.files?.[0]) sendFileHC(e.target.files?.[0]);
                                        }}
                                        style={{ display: "none" }}
                                        type="file"
                                    />
                                    <AttachFileIcon sx={{ color: theme.palette.golden.main }} />
                                </IconButton>
                            </InputAdornment>
                        )
                    }}
                    InputLabelProps={{
                        style: {
                            color: theme.palette.secondary.main,
                        }
                    }}
                />
            }
        </Box>
    );
}
