import { useDialog } from "@/app/providers/DialogProvider/useDialog";
import { useRosettaColors } from "@/app/hooks/useRosettaColors";
import { Box, Divider, Flex, Menu, Popover, Text, Transition, useComputedColorScheme } from "@mantine/core";
import { IconBarrierBlock, IconCamera, IconDoorExit, IconFile, IconMoodSmile, IconPaperclip, IconSend } from "@tabler/icons-react";
import { useEffect, useRef, useState } from "react";
import { useBlacklist } from "@/app/providers/BlacklistProvider/useBlacklist";
import { base64ImageToBlurhash, filePrapareForNetworkTransfer, generateRandomKey, imagePrepareForNetworkTransfer } from "@/app/utils/utils";
import { Attachment, AttachmentType } from "@/app/providers/ProtocolProvider/protocol/packets/packet.message";
import { DialogAttachment } from "../DialogAttachment/DialogAttachment";
import { PacketTyping } from "@/app/providers/ProtocolProvider/protocol/packets/packet.typeing";
import { usePublicKey } from "@/app/providers/AccountProvider/usePublicKey";
import { usePrivateKeyHash } from "@/app/providers/AccountProvider/usePrivateKeyHash";
import { useSender } from "@/app/providers/ProtocolProvider/useSender";
import { useReplyMessages } from "@/app/providers/DialogProvider/useReplyMessages";
import { useFileDialog, useHotkeys } from "@mantine/hooks";
import { ATTACHMENTS_NOT_ALLOWED_TO_REPLY, MAX_ATTACHMENTS_IN_MESSAGE, MAX_UPLOAD_FILESIZE_MB } from "@/app/constants";
import { useSystemAccounts } from "@/app/providers/SystemAccountsProvider/useSystemAccounts";
import { Dropzone } from '@mantine/dropzone';
import { RichTextInput } from "../RichTextInput/RichTextInput";
import EmojiPicker, { EmojiClickData, Theme } from 'emoji-picker-react';
import { useAvatars } from "@/app/providers/AvatarProvider/useAvatars";
import { useGroups } from "@/app/providers/DialogProvider/useGroups";
import { useGroupMembers } from "@/app/providers/InformationProvider/useGroupMembers";
import { AnimatedButton } from "../AnimatedButton/AnimatedButton";
import { useUserCacheFunc } from "@/app/providers/InformationProvider/useUserCacheFunc";
import { MentionList, Mention } from "../MentionList/MentionList";
import { useDrafts } from "@/app/providers/DialogProvider/useDrafts";


export function DialogInput() {
    const colors = useRosettaColors();
    const {sendMessage, dialog} = useDialog();
    const {members, loading} = useGroupMembers(dialog);
    const {hasGroup, leaveGroup} = useGroups();
    const [message, setMessage] = useState<string>("");
    const [blocked] = useBlacklist(dialog);
    const [attachments, setAttachments] = useState<Attachment[]>([]);
    const publicKey = usePublicKey();
    const isAdmin = hasGroup(dialog) && members[0] == publicKey;
    const isBannedGroup = hasGroup(dialog) && members.length == 0 && !loading;
    const privateKey = usePrivateKeyHash();
    const sendPacket = useSender();
    const typingTimeoutRef = useRef<NodeJS.Timeout | null>(null);
    const {replyMessages, deselectAllMessages} = useReplyMessages();
    const computedTheme = useComputedColorScheme();
    const systemAccounts = useSystemAccounts();
    const [mentionList, setMentionList] = useState<Mention[]>([]);
    const mentionHandling = useRef<string>("");
    const {getDraft, saveDraft} = useDrafts(dialog);

    
    const avatars = useAvatars(
        hasGroup(dialog) ? dialog : publicKey
        , false);

    const editableDivRef = useRef<any>(null);
    const getUserFromCache = useUserCacheFunc();
    const regexp = new RegExp(/@([\w\d_]{3,})$/);

    useHotkeys([
        ['Esc', () => {
            setAttachments([]);
        }]
    ], [], true);

    const fileDialog = useFileDialog({
        multiple: false,
        //naccept: '*',
        onChange: async (files) => {
            if(!files){
                return;
            }
            if(files.length == 0){
                return;
            }
            if(attachments.length >= MAX_ATTACHMENTS_IN_MESSAGE){
                return;
            }
            if(attachments.find(a => ATTACHMENTS_NOT_ALLOWED_TO_REPLY.includes(a.type))){
                return;
            }
            const file = files[0];
            if(((file.size / 1024) / 1024) > MAX_UPLOAD_FILESIZE_MB){
                return;
            }
            const fileContent = await filePrapareForNetworkTransfer(file);
            setAttachments([...attachments, {
                blob: fileContent,
                id: generateRandomKey(8),
                type: AttachmentType.FILE,
                preview: files[0].size + "::" + files[0].name
            }]);
        }
    });

    useEffect(() => {
        const draftMessage = getDraft();
        console.info("GET DRAFT", draftMessage);
        if(draftMessage == "" || !editableDivRef){
            return;
        }
        setMessage(draftMessage);
        editableDivRef.current.insertHTMLInCurrentCarretPosition(draftMessage);
    }, [dialog, editableDivRef]);

    useEffect(() => {
        if(replyMessages.inDialogInput && replyMessages.inDialogInput == dialog){
            setAttachments([{
                type: AttachmentType.MESSAGES,
                id: generateRandomKey(8),
                blob: JSON.stringify([...replyMessages.messages]),
                preview: ""
            }]);
            editableDivRef.current.focus();
        }
    }, [dialog, replyMessages]);

    useEffect(() => {
        saveDraft(message);
        if(regexp.test(message) && hasGroup(dialog)){
            const username = regexp.exec(message);
            if(!username){
                return;
            }
            if(username[1].length > 2){
                handleMention(username[1]);
            }
        }else{
            setMentionList([]);
        }
    }, [message]);


    if(systemAccounts.find((acc) => acc.publicKey == dialog)){
        return <></>;
    }

    const handleMention = async (username: string) => {
        const regexpToFindAllMentionedUsernames = new RegExp(`@([\\w\\d_]{2,})`, 'g');
        const mentionedUsernamesInMessage = message.match(regexpToFindAllMentionedUsernames);


        const mentionsList : Mention[] = [];
        
        if(!isAdmin && username.startsWith('adm') && (mentionedUsernamesInMessage && !mentionedUsernamesInMessage.includes('@admin'))){
            mentionsList.push({
                username: 'admin',
                title: 'Administrator',
                publicKey: ''
            });
        }

        for(let i = 0; i < members.length; i++){
            const userInfo = await getUserFromCache(members[i]);
            if(!userInfo){
                continue;
            }
            if(!userInfo.username.startsWith(username)){
                continue;
            }
            if(mentionedUsernamesInMessage && mentionedUsernamesInMessage.includes(`@${userInfo.username}`)){
                continue;
            }
            mentionsList.push({
                username: userInfo.username,
                title: userInfo.title,
                publicKey: userInfo.publicKey
            });
        }
        setMentionList(mentionsList);
        mentionHandling.current = username;
    }

    const send = () => {
        if(blocked || (message.trim() == "" && attachments.length <= 0)) {
            return;
        }
        sendMessage(message, attachments);
        editableDivRef.current.clear();      
        setAttachments([]);
        deselectAllMessages();
    }

    const handleKeyDown = (event: React.KeyboardEvent) => {
        if (event.key === 'Enter' && !event.shiftKey) {
            event.preventDefault();
            if(mentionList.length <= 0){
                send();
            }
        }
        if (!event.shiftKey && event.key.length === 1 && !blocked) {
            if (!typingTimeoutRef.current) {
                sendTypeingPacket();
                typingTimeoutRef.current = setTimeout(() => {
                    typingTimeoutRef.current = null;
                }, 3000);
            }
        }
    };

    const onRemoveAttachment = (attachment: Attachment) => {
        setAttachments(attachments.filter(a => a.id != attachment.id));
        editableDivRef.current.focus();
    }

    const onClickPaperclip = () => {
        fileDialog.open(); 
    }

    const onClickCamera = async () => {
        if(avatars.length == 0){
            return;
        }
        setAttachments([{
            blob: avatars[0].avatar,
            id: generateRandomKey(8),
            type: AttachmentType.AVATAR,
            preview: await base64ImageToBlurhash(avatars[0].avatar)
        }]);
        editableDivRef.current.focus();
    }

    const sendTypeingPacket = () => {
        let packet = new PacketTyping();
        packet.setToPublicKey(dialog);
        packet.setFromPublicKey(publicKey);
        packet.setPrivateKey(privateKey);
        sendPacket(packet);
    }

    const onPaste = async (event: React.ClipboardEvent) => {
        if(systemAccounts.find((acc) => acc.publicKey == dialog)){
            /**
             * У системных аккаунтов нельзя вызывать вложения
             */
            return;
        }
        if(attachments.length >= MAX_ATTACHMENTS_IN_MESSAGE){
            return;
        }
        if(attachments.find(a => ATTACHMENTS_NOT_ALLOWED_TO_REPLY.includes(a.type))){
            return;
        }
        const items = event.clipboardData.items;
        for (let i = 0; i < items.length; i++) {
            const item = items[i];
            if (item.type.startsWith("image/")) {
                const file = item.getAsFile();
                if (file) {
                    const base64Image = await imagePrepareForNetworkTransfer(file);
                    setAttachments([...attachments, {
                        blob: base64Image,
                        id: generateRandomKey(8),
                        type: AttachmentType.IMAGE,
                        preview: await base64ImageToBlurhash(base64Image)
                    }]);
                }
                if(editableDivRef.current){
                    editableDivRef.current.focus();
                }
                break;
            }
        }
    }

    const onDragAndDrop = async (files : File[]) => {
        if(!files){
            return;
        }
        if(files.length == 0){
            return;
        }
        if(attachments.length >= MAX_ATTACHMENTS_IN_MESSAGE){
            return;
        }
        if(files.length > 1){
            return;
        }
        const file = files[0];
        if(((file.size / 1024) / 1024) > MAX_UPLOAD_FILESIZE_MB){
            return;
        }
        let fileContent = await filePrapareForNetworkTransfer(file);
        setAttachments([...attachments, {
            blob: fileContent,
            id: generateRandomKey(8),
            type: AttachmentType.FILE,
            preview: files[0].size + "::" + files[0].name
        }]);
    }

    const onEmojiClick = (emojiData : EmojiClickData) => {
        editableDivRef.current.insertHTML(
            `<img alt=":emoji_${emojiData.unified}:" height="20" width="20" data=":emoji_${emojiData.unified}:" src="${emojiData.imageUrl}" />`
        );
    }

    const onSelectMention = (mention : Mention) => {
        editableDivRef.current.insertHTMLInCurrentCarretPosition(mention.username.substring(mentionHandling.current.length));
        mentionHandling.current = "";
    }

    return (
        <>
        <Transition 
            transition={'fade-down'} 
            mounted={mentionList.length > 0}>
            {(styles) => (
                <MentionList onSelectMention={onSelectMention} style={{...styles}} mentions={mentionList}></MentionList>
            )}
        </Transition>
        {attachments.length > 0 &&  
        <Flex direction={'row'} wrap={'wrap'} p={'sm'} gap={'sm'}>
            {attachments.map((m) => (
                <DialogAttachment onRemove={onRemoveAttachment} attach={m} key={m.id}></DialogAttachment>
            ))}                    
        </Flex>}
        <Dropzone.FullScreen active={true} onDrop={onDragAndDrop}>
            <Flex justify={'center'} align={'center'} mih={document.body.clientHeight - 60} style={{ pointerEvents: 'none' }}>
                <Text ta={'center'} size={'md'}>Drop files here to attach without compression</Text>
            </Flex>
        </Dropzone.FullScreen>
        {!isBannedGroup && (
        <Box bg={colors.boxColor}>
            <Divider color={colors.borderColor}></Divider>
            {!blocked && 
            <Flex h={'100%'} p={'xs'} direction={'row'} bg={colors.boxColor}>
                <Flex w={25} mt={10} justify={'center'}>
                    <Menu width={150} withArrow>
                        <Menu.Target>
                            <IconPaperclip stroke={1.5} style={{
                                cursor: 'pointer'
                            }} size={25} color={colors.chevrons.active}></IconPaperclip>
                        </Menu.Target>
                        <Menu.Dropdown style={{
                            userSelect: 'none'
                        }}>
                            <Menu.Label fz={'xs'} fw={500} c={'dimmed'}>Attach</Menu.Label>
                            <Menu.Item fz={'xs'} fw={500} leftSection={
                                <IconFile size={14}></IconFile>
                            } onClick={onClickPaperclip}>File</Menu.Item>
                            {((avatars.length > 0 && !hasGroup(dialog)) 
                            || (avatars.length > 0 && hasGroup(dialog) && isAdmin)) 
                            && <Menu.Item fz={'xs'} fw={500} leftSection={
                                <IconCamera size={14}></IconCamera>
                            } onClick={onClickCamera}>Avatar {hasGroup(dialog) && 'group'}</Menu.Item>}
                        </Menu.Dropdown>
                    </Menu>
                </Flex>
                <Flex 
                    w={'calc(100% - (25px + 50px + var(--mantine-spacing-xs)))'} 
                    maw={'calc(100% - (25px + 50px + var(--mantine-spacing-xs)))'} 
                    align={'center'}
                >
                    <RichTextInput
                        ref={editableDivRef}
                        style={{
                            border: 0,
                            minHeight: 45,
                            fontSize: 14,
                            background: 'transparent',
                            width: '100%',
                            paddingLeft: 10,
                            paddingRight: 10,
                            outline: 'none',
                            paddingTop: 10,
                            paddingBottom: 8
                        }}
                        placeholder="Type message..."
                        autoFocus
                        //ref={textareaRef}
                        //onPaste={onPaste}
                        //maxLength={2500}
                        //w={'100%'}
                        //h={'100%'}
                        onKeyDown={handleKeyDown}
                        onChange={setMessage}
                        onPaste={onPaste}
                        
                        //dangerouslySetInnerHTML={{__html: message}}
                    ></RichTextInput>                             
                </Flex>
                <Flex mt={10} w={'calc(50px + var(--mantine-spacing-xs))'} gap={'xs'}>
                    <Popover withArrow>
                        <Popover.Target>
                            <IconMoodSmile color={colors.chevrons.active} stroke={1.5} size={25} style={{
                                cursor: 'pointer'
                            }}></IconMoodSmile>
                        </Popover.Target>
                        <Popover.Dropdown p={0}>
                            <EmojiPicker 
                                onEmojiClick={onEmojiClick}
                                searchDisabled
                                skinTonesDisabled
                                theme={computedTheme == 'dark' ? Theme.DARK : Theme.LIGHT} 
                            />
                        </Popover.Dropdown>
                    </Popover>
                    <IconSend stroke={1.5} color={message.trim() == "" && attachments.length <= 0 ? colors.chevrons.active : colors.brandColor} onClick={send} style={{
                        cursor: 'pointer'
                    }} size={25}></IconSend>
                </Flex>
            </Flex>}
            {blocked && <Box mih={62} bg={colors.boxColor}>
                <Flex align={'center'} justify={'center'} h={62}>
                    <Flex gap={'sm'} align={'center'} justify={'center'}>
                        <IconBarrierBlock size={24} color={colors.error} stroke={1.2}></IconBarrierBlock>
                        <Text ta={'center'} c={'dimmed'} size={'xs'}>You need unblock user for send messages.</Text>
                    </Flex>
                </Flex>
            </Box>}
        </Box>            
        )}
        {isBannedGroup && (
            <Flex align={'center'} bg={colors.boxColor} justify={'center'}>
                <AnimatedButton onClick={() => {
                    leaveGroup(dialog)
                }} animated={[
                    '#ff5656',
                    '#e03131'
                ]} color="red" animationDurationMs={1000} w={'80%'} size={'sm'} radius={'xl'} leftSection={
                    <IconDoorExit size={15} />
                } mb={'md'}>Leave</AnimatedButton>
            </Flex>
        )}
        </>
    )
}