import { useContext, useEffect, useState } from "react";
import { InformationContext, UserInformation } from "./InformationProvider";
import { PacketOnlineSubscribe } from "@/app/providers/ProtocolProvider/protocol/packets/packet.onlinesubscribe";
import { useMemory } from "../MemoryProvider/useMemory";
import { OnlineState } from "@/app/providers/ProtocolProvider/protocol/packets/packet.onlinestate";
import { PacketSearch } from "@/app/providers/ProtocolProvider/protocol/packets/packet.search";
import { usePrivateKeyHash } from "../AccountProvider/usePrivateKeyHash";
import { useSender } from "../ProtocolProvider/useSender";
import { usePacket } from "../ProtocolProvider/usePacket";
import { usePublicKey } from "../AccountProvider/usePublicKey";
import { useBlacklist } from "../BlacklistProvider/useBlacklist";
import { useConsoleLogger } from "@/app/hooks/useConsoleLogger";
import { useSystemAccounts } from "../SystemAccountsProvider/useSystemAccounts";

export function useUserInformation(publicKey: string) : [
    UserInformation,
    (userInfo: UserInformation) => Promise<void>,
    () => void, 
    boolean
] {
    const context = useContext(InformationContext);
    const send = useSender();
    const privateKey = usePrivateKeyHash();
    const [onlineSubscribes, setOnlineSubscribes] = useMemory<string[]>("online_subscribes", [], true);
    const {cachedUsers, updateUserInformation} = context;
    const user : UserInformation = cachedUsers.find((user: UserInformation) => user.publicKey == publicKey);
    const [loading, setLoading] = useState(false);
    const ownPublicKey = usePublicKey();
    const [blocked] = useBlacklist(publicKey);
    const {info, warn} = useConsoleLogger('useUserInformation');
    const systemAccounts = useSystemAccounts();

    if(!context || !context.cachedUsers) {
        throw new Error("useUserInformation must be used within a InformationProvider");
    }

    const forceUpdateUserInformation = () => {
        if(publicKey.indexOf("#group:") !== -1){
            /**
             * This is group, only users can be force updated
             */
            info("Force update skipped for group " + publicKey);
            return;
        }
        if(systemAccounts.find((acc) => acc.publicKey == publicKey)){
            /**
             * System account has no updates, its hardcoded display
             * name and user name
             */
            info("System account not need force update");
            return;
        }
        if(blocked){
            warn("User is blocked, no force update " + publicKey);
            return;
        }
        warn("Force update " + publicKey);
        let packetSearch = new PacketSearch();
        packetSearch.setSearch(publicKey);
        packetSearch.setPrivateKey(privateKey);
        send(packetSearch);
    }

    useEffect(() => {
        /**
         * Подписываемся на статус пользователя онлайн или не онлайн 
         * если еще не подписаны
         */
        if(systemAccounts.find((acc) => acc.publicKey == publicKey)){
            /**
             * У системных аккаунтов не нужно подписыаться на онлайн статус
             */
            return;
        }        
        if(onlineSubscribes.indexOf(publicKey) !== -1 
            || publicKey.indexOf("#group:") !== -1
            || publicKey == ownPublicKey 
            || publicKey.trim() == ''
            || blocked){
            /**
             * Уже подписаны на онлайн статус этого пользователя или это группа
             */
            return;
        }
        let subscribePacket = new PacketOnlineSubscribe();
        subscribePacket.setPrivateKey(privateKey);
        subscribePacket.addPublicKey(publicKey);
        send(subscribePacket);
        setOnlineSubscribes((prev) => [...prev, publicKey]);
    }, [blocked, publicKey]);

    useEffect(() => {
        if(user || publicKey.trim() == ''){
            return;
        }
        if(systemAccounts.find((acc) => acc.publicKey == publicKey)){
            /**
             * System account has no updates, its hardcoded display
             * name and user name
             */
            return;
        }
        setLoading(true);
        let packetSearch = new PacketSearch();
        packetSearch.setSearch(publicKey);
        packetSearch.setPrivateKey(privateKey);
        send(packetSearch);
    }, [publicKey, privateKey, user]);
    
    usePacket(0x03, (packet : PacketSearch) => {
        const users = packet.getUsers();
        if (users.length > 0 && users[0].publicKey == publicKey) {
            if( user &&
                user.username == users[0].username &&
                user.verified == users[0].verified &&
                user.title == users[0].title
            ){
                /**
                 * No update readed from server, stop rerender
                 */
                return;
            }
            setLoading(false);
            updateUserInformation({
                publicKey: users[0].publicKey,
                avatar: "", // No avatar in search packet
                username: users[0].username,
                title: users[0].title,
                online: users[0].online,
                verified: users[0].verified
            });
        }
    }, [publicKey, privateKey]);

    let userInfo = user ? user : {
        title: "DELETED",
        username: "",
        publicKey: "",
        online: OnlineState.OFFLINE,
        verified: 0
    };

    if(systemAccounts.find((acc) => acc.publicKey == publicKey)){
        /**
         * Это системный аккаунт, возвращаем его информацию
         */
        userInfo = systemAccounts.find((acc) => acc.publicKey == publicKey)!;
    }

    return [
        userInfo, updateUserInformation, forceUpdateUserInformation, loading
    ]
  
}