import { createContext, useEffect, useRef, useState } from "react";
import { PacketRequestTransport } from "../ProtocolProvider/protocol/packets/packet.requesttransport";
import { useSender } from "../ProtocolProvider/useSender";
import { usePacket } from "../ProtocolProvider/usePacket";
import { useConsoleLogger } from "@/app/hooks/useConsoleLogger";

interface TransportContextValue {
    transportServer: string | null;
    uploadFile: (id: string, content: string) => Promise<any>;
    downloadFile: (id: string, tag: string, transportServer: string) => Promise<string>;
    uploading: TransportState[];
    downloading: TransportState[];
}

export const TransportContext = createContext<TransportContextValue | null>(null);

interface TransportProviderProps {
    children: React.ReactNode;
}

export interface TransportState {
    id: string;
    progress: number;
}

/**
 * Этот провайдер занимается тем, что передает
 * файлы на сервер и получает их с сервера
 */
export function TransportProvider(props: TransportProviderProps) {
    const transportServerRef = useRef<string | null>(null);
    const [uploading, setUploading] = useState<TransportState[]>([]);
    const [downloading, setDownloading] = useState<TransportState[]>([]);
    const send = useSender();
    const { info } = useConsoleLogger('TransportProvider');

    useEffect(() => {
        let packet = new PacketRequestTransport();
        send(packet);
    }, []);

    usePacket(0x0F, (packet: PacketRequestTransport) => {
        transportServerRef.current = packet.getTransportServer();
        info(`Transport server ${transportServerRef.current}`);
    });

    const uploadFile = async (id: string, content: string) => {
        return new Promise((resolve, reject) => {
            if (!transportServerRef.current) {
                throw new Error("Transport server is not set");
            }
            setUploading(prev => [...prev, { id: id, progress: 0 }]);
            const formData = new FormData();
            formData.append('file', new Blob([content]), id);

            const xhr = new XMLHttpRequest();
            xhr.open('POST', `${transportServerRef.current}/u`);

            xhr.upload.onprogress = (event) => {
                if (event.lengthComputable) {
                    const progress = Math.round((event.loaded / event.total) * 100);
                    setUploading(prev =>
                        prev.map(u =>
                            u.id === id ? { ...u, progress } : u
                        )
                    );
                }
            };

            xhr.onload = () => {
                resolve(JSON.parse(xhr.responseText).t);
                setUploading(prev => prev.filter(u => u.id !== id));
            };

            xhr.onerror = () => {
                reject();
                setUploading(prev => prev.filter(u => u.id !== id));
            };

            xhr.send(formData);
        });
    }

    /**
     * Скачивает файл с транспортного сервера
     * @param tag тег файла
     * @param chachaDecryptedKey ключ для расшифровки файла
     */
    const downloadFile = (id: string, tag : string, transportServer: string) : Promise<string> => {
        return new Promise((resolve, reject) => {
            if (!transportServer) {
                throw new Error("Transport server is not set");
            }
            setDownloading(prev => [...prev, { id: id, progress: 0 }]);
            const xhr = new XMLHttpRequest();
            xhr.open('GET', `${transportServer}/d/${tag}`);
            xhr.responseType = 'text';

            xhr.onprogress = (event) => {
                if (event.lengthComputable) {
                    const progress = Math.round((event.loaded / event.total) * 100);
                    setDownloading(prev =>
                        prev.map(u =>
                            u.id === id ? { ...u, progress } : u
                        )
                    );
                }
            };

            xhr.onload = async () => {
                if(xhr.status != 200){
                    reject();
                    return;
                }
                setDownloading(prev => prev.filter(u => u.id !== tag));
                let blob = xhr.responseText;
                resolve(blob);
            };

            xhr.onerror = () => {
                setDownloading(prev => prev.filter(u => u.id !== tag));
                reject();
            };

            xhr.send();            
        });
    }

    return (
        <TransportContext.Provider value={{
            transportServer: transportServerRef.current,
            uploadFile,
            downloadFile,
            uploading,
            downloading
        }}>
            {props.children}
        </TransportContext.Provider>
    )
}