import React, {useState, useEffect} from "react";
import {createRoot} from 'react-dom/client';
import {marked} from "marked";
import gsap from "gsap";
import Swal from "sweetalert2";


const Chat = () => {
    const [initialPrompt, setInitialPrompt] = useState('');
    const [firstMsg, setFirstMsg] = useState('');
    const [appReady, setAppReady] = useState(false);
    const [responses, setResponses] = useState([]);
    const [message, setMessage] = useState("");
    const [textFlowing, setTextFlowing] = useState(false);

    const [tokensIn, setTokensIn] = useState(0);
    const [tokensOut, setTokensOut] = useState(0);
    const [source, setSource] = useState('');
    const [sourceTokens, setSourceTokens] = useState(0);
    const [model, setModel] = useState("gpt-4o-mini");
    const [spend, setSpend] = useState(0);
    const [loading, setLoading] = useState(false);
    const [preset, setPreset] = useState("");
    const [messages, setMessages] = useState([]);
    const [threadId, setThreadId] = useState(false);

    const [chatOpen, setChatOpen] = useState(false);
    const [chatStarted, setChatStarted] = useState(false);

    const charactersPerToken = 4;

    let apiUrl = "https://chat.webien.io/api";
    if (window.location.hostname.includes('.test')) {
        apiUrl = "http://localhost:3000";
    }

/*
    let jsonString = '{"id":"msg_LQ6fe3beJnXM3R4CLQ7F4gxu","object":"thread.message","created_at":1746628418,"assistant_id":"asst_ujrO80kea9G6pQhJApkJPqXC","thread_id":"thread_jaVtmzIadrlV0XlBQkDhfGR1","run_id":"run_hzATroF9mmsz5BTDaeFGpowF","status":"completed","incomplete_details":null,"incomplete_at":null,"completed_at":1746628429,"role":"assistant","content":[{"type":"text","text":{"value":"När du flyttar ut är det viktigt att tänka på flera olika steg för att säkerställa en smidig övergång. Här är några viktiga punkter att tänka på:\\n\\n### 1. **Säga upp kontraktet**\\n   - Uppsägning ska ske genom uppsägning via Mina sidor och signeras med Bank-ID eller skriftligt. För mer information om hur man säger upp sitt kontrakt, besök [denna länk](https://www.skovdebostader.se/hyresgastguiden/uppsagning/)【4:8†source】.\\n\\n### 2. **Återställning av lägenheten**\\n   - Du ansvarar för att lägenheten är återställd i ursprungsskick innan kontraktet löper ut. Se över städningen och eventuella reparationer【4:1†source】.\\n\\n### 3. **Flyttanmälan**\\n   - Gör en flyttanmälan till Skatteverket så att din folkbokföringsadress blir korrekt. Detta är gratis och kan göras på [skattemyndighetens webbplats](https://www.skatteverket.se/flytta)【4:15†source】.\\n\\n### 4. **Säga upp abonnemang**\\n   - Kom ihåg att säga upp olika abonnemang som el, TV och internet. Detta är viktigt för att säkerställa att du inte fortsatt belastas för tjänster i en lägenhet du inte längre bor i【4:19†source】.\\n\\n### 5. **Nycklar och besiktning**\\n   - Om du har mottagit nycklar direkt från den avflyttande hyresgästen, se till att skriva på nyckelkvittensen hos kvartersvärden så snart som möjligt. När du flyttar ut kan en städbesiktning ske, så det kan vara bra att ha allt klart innan dess【4:5†source】【4:6†source】.\\n\\n### 6. **Porttelefon och annan service**\\n   - Om du bor i ett område med porttelefon, meddela din kvartersvärd vilket telefonnummer du vill ha kopplat till porttelefonen【4:2†source】.\\n\\nAtt följa dessa steg kan hjälpa till att göra din flytt och avflyttningsprocess smidig och utan komplikationer.","annotations":[{"type":"file_citation","text":"【4:8†source】","start_index":410,"end_index":422,"file_citation":{"file_id":"file-TaEqwGsWygBQrCRjcAck5M"}},{"type":"file_citation","text":"【4:1†source】","start_index":604,"end_index":616,"file_citation":{"file_id":"file-TaEqwGsWygBQrCRjcAck5M"}},{"type":"file_citation","text":"【4:15†source】","start_index":831,"end_index":844,"file_citation":{"file_id":"file-TaEqwGsWygBQrCRjcAck5M"}},{"type":"file_citation","text":"【4:19†source】","start_index":1061,"end_index":1074,"file_citation":{"file_id":"file-TaEqwGsWygBQrCRjcAck5M"}},{"type":"file_citation","text":"【4:5†source】","start_index":1357,"end_index":1369,"file_citation":{"file_id":"file-TaEqwGsWygBQrCRjcAck5M"}},{"type":"file_citation","text":"【4:6†source】","start_index":1369,"end_index":1381,"file_citation":{"file_id":"file-TaEqwGsWygBQrCRjcAck5M"}},{"type":"file_citation","text":"【4:2†source】","start_index":1553,"end_index":1565,"file_citation":{"file_id":"file-TaEqwGsWygBQrCRjcAck5M"}}]}}],"attachments":[],"metadata":{}}';

    let val = JSON.parse(jsonString).content[0].text.value;
    val.split("\n").forEach((line) => {
        console.log(line);
    });
 */


    //console.log(JSON.parse(jsonString).content[0].text.value);


    const getSpend = function () {

        if (tokensIn === 0 || tokensOut === 0) return 0;
        let currentModel = models.filter((item) => item.name === model)[0];

        // Cost is per million tokens
        let costIn = (currentModel.costIn / 1000000) * tokensIn;
        let costOut = (currentModel.costOut / 1000000) * tokensOut;

        let dollarSek = 10.2;

        //return Math.round(costIn + costOut) / 100000;
        return ((costIn + costOut) * dollarSek).toFixed(5);
    }

    async function getSourceTokens() {
        if (source === '') return 0;
        let json = await fetchJsonFromUrl(source);
        let str = JSON.stringify(json);

        setSourceTokens(prevCount => formatNumber(Math.round(str.length / charactersPerToken)));
    }


    const models = [
        {
            name: 'gpt-4o',
            costIn: 2.5,
            costOut: 10
        },
        {
            name: 'gpt-4-turbo',
            costIn: 10,
            costOut: 30
        },
        {
            name: 'gpt-4o-mini',
            costIn: 0.15,
            costOut: 0.6
        },
        {
            name: 'gpt-3.5-turbo',
            costIn: 3.0,
            costOut: 6.0
        },
    ];

    useEffect(() => {
        setAppReady(true);
        init();
    }, []);

    useEffect(() => {
        if (source) {
            getSourceTokens();
        }
    }, [source]);


    useEffect(() => {
        if (loading) {
            scrollToBottom();
        }
    }, [loading]);

    const formatNumber = function (number) {
        return Intl.NumberFormat('sv-SE').format(number);
    }



    const init = () => {
        setInitialPrompt(webienAi.systemPrompt);
        setSource(prev => webienAi.file);
        setFirstMsg(prev => webienAi.firstMsg);
        setModel(webienAi.model);
        getThread();

        setTimeout(() => {
            document.querySelector(".input-form input").focus();
        }, 500);
    };



    const Loader = () => {
        return (
            <svg width="120" height="30" viewBox="0 0 120 30" xmlns="http://www.w3.org/2000/svg" fill="#000">
                <circle cx="15" cy="15" r="15">
                    <animate attributeName="r" from="15" to="15"
                             begin="0s" dur="0.8s"
                             values="15;9;15" calcMode="linear"
                             repeatCount="indefinite"/>
                    <animate attributeName="fill-opacity" from="1" to="1"
                             begin="0s" dur="0.8s"
                             values="1;.5;1" calcMode="linear"
                             repeatCount="indefinite"/>
                </circle>
                <circle cx="60" cy="15" r="9" fillOpacity="0.3">
                    <animate attributeName="r" from="9" to="9"
                             begin="0s" dur="0.8s"
                             values="9;15;9" calcMode="linear"
                             repeatCount="indefinite"/>
                    <animate attributeName="fill-opacity" from="0.5" to="0.5"
                             begin="0s" dur="0.8s"
                             values=".5;1;.5" calcMode="linear"
                             repeatCount="indefinite"/>
                </circle>
                <circle cx="105" cy="15" r="15">
                    <animate attributeName="r" from="15" to="15"
                             begin="0s" dur="0.8s"
                             values="15;9;15" calcMode="linear"
                             repeatCount="indefinite"/>
                    <animate attributeName="fill-opacity" from="1" to="1"
                             begin="0s" dur="0.8s"
                             values="1;.5;1" calcMode="linear"
                             repeatCount="indefinite"/>
                </circle>
            </svg>
        )
    }

    const openChat = () => {
        setChatOpen(true);
        setTimeout(() => {
            document.querySelector(".input-form input").focus();
            scrollToBottom();
        }, 100);


        // Set the available height of the chat container (Widget mode)
        setChatDimensions();


        // Listen for resize events to adjust chat dimensions
        window.addEventListener('resize', () => {
            setChatDimensions();
            scrollToBottom();
        })


        // Add class to html to prevent scrolling
        document.querySelector("html").classList.add("webien-chat-open");
    }

    const closeChat = () => {
        setChatOpen(false);
        setChatStarted(false);
        document.querySelector("html").classList.remove("webien-chat-open");
    }

    const setChatDimensions = () => {

        const chatContainer = document.querySelector(".elementor-widget-webien_ai_prompt");

        if (chatContainer) {
            // First set the height to auto to calculate the correct height
            chatContainer.style.height = 'auto';
            // Get height of closest parent
            const parent = chatContainer.closest('div');
            if (parent) {
                const height = parent.clientHeight; // Subtract 50px for header and input

                // Account for admin bar
                const adminBarHeight = document.querySelector('#wpadminbar') ? document.querySelector('#wpadminbar').offsetHeight : 0;

                chatContainer.style.height = `${height - adminBarHeight}px`;
            }
        }
    }

    const saveThread = (threadId) => {
        setThreadId(threadId);
        // Save to local storage
        let object = { threadId: threadId, updated: Date.now() };
        localStorage.setItem('webien-ai-thread', JSON.stringify(object));
    }

    const getThread = () => {

        // Get thread from local storage
        let thread = localStorage.getItem('webien-ai-thread');
        if(thread) {

            // If not a valid object
            if(!isJson(thread)) {
                localStorage.removeItem('webien-ai-thread');
                setThreadId(false);
                return;
            }

            thread = JSON.parse(thread);

            // Check if thread is older than 1 day
            let now = Date.now();
            let diff = now - thread.updated;
            if(diff > (3600000 * 24)) {
                // Remove thread id in local storage
                localStorage.removeItem('webien-ai-thread');
                setThreadId(false);
                return;
            }
            // Else set thread id
            setThreadId(thread.threadId);



            // Get existing messages
            if(thread.hasOwnProperty('messages')) {
                setMessages(thread.messages);

                setTimeout(() => {
                    scrollToBottom();
                }, 100);


            } else {
                setMessages([]);

            }
        } else {
            // No existing thread
            // Set welcome animation preset
            gsap.set('.assistant.first-msg', {
                yPercent: 100,
            });

            // Animate welcome message
            gsap.to('.assistant.first-msg', {
                opacity: 1,
                yPercent: 0,
                duration: 1.3,
                delay: 0.3,
                ease: 'elastic',
            });

        }

    }


    const isJson = (str) => {
        try {
            JSON.parse(str);
        } catch (e) {
            return false;
        }
        return true;
    }

    const scrollToBottom = () => {
        const chat = document.querySelector(".webien-ai .chat");
        if (chat) {
            chat.scrollTo({
                top: chat.scrollHeight,
                behavior: "smooth",
            });
        }
    }


    const checkMessage = (e) => {
        if (e.key === "Enter") {
            sendMessageToAI();
        }
    }


    async function fetchJsonFromUrl(url) {
        const response = await fetch(url);
        if (!response.ok) throw new Error(`HTTP-fel! Status: ${response.status}`);
        return await response.json();
    }

    const resetThread = () => {
        // Remove thread id in local storage
        localStorage.removeItem('webien-ai-thread');
        setThreadId(false);
        setMessages([]);
        setResponses([]);
        scrollToBottom();
    }


    const sendMessageToAI = async () => {

        // Return if message is empty
        if (message === '') {
            document.querySelector(".input-form input").focus();
            return;
        }


        if (!responses.length && (source === '' || initialPrompt === '')) {
            alert("Du behöver skicka med en prompt och en json källa.");
            return;
        }

        setLoading(true);
        setChatStarted(true);

        // Start the chat if not already started
        openChat();



        const responseIndex = responses.length;
        setResponses((prevResponses) => [...prevResponses, ""]);

        // Update tokensIn (Grov uppskattning 1 token = 4 tecken)

        // Push this message to the messages array
        messages.push({role: "user", content: message});

        setTokensIn(prevCount => prevCount + (message.length / charactersPerToken));

        messages.forEach((msg) => {
            setTokensIn(prevCount => prevCount + (msg.content.length / charactersPerToken));
        });


        setMessage("");

        scrollToBottom();


        try {
            const response = await fetch(apiUrl + '/thread', {
                method: "POST",
                headers: {
                    "Content-Type": "application/json",
                    "Authorization": webienAi.apiKey
                },

                // Threads
                body: JSON.stringify({
                    messages : messages,
                    assistant: webienAi.assistant,
                    threadId: threadId,
                }),
            });

            if (response.status === 401) {
                // Visa något i UI:t, redirect till login, etc.
                setResponses((prevResponses) => {
                    const newResponses = [...prevResponses];
                    newResponses[responseIndex] += 'Fel: API-nyckeln är ogiltig. Kontakta  en administratör.';
                    return newResponses;
                });

                setLoading(false);
                return;
            }

            if (response.status === 400) {

                // Something went wrong on the server
                // Lets handle some scenarios
                const errorData = await response.json();


                if(errorData.error.includes('Vector store')) {
                    // Vector store is most likely expired..

                    jQuery.ajax({
                        type : "post",
                        dataType : "json",
                        url : webienAiHelpers.ajaxurl,
                        data:{
                            'action': 'webien_ai_generate',
                        },
                        success: function(data){
                            //console.log(data);
                            // Remove thread id in local storage
                            localStorage.removeItem('webien-ai-thread');
                            setThreadId(false);

                            sendMessageToAI();
                        }
                    });


                }


                return;
            }


            const reader = response.body.getReader();
            const decoder = new TextDecoder("utf-8");


            const readStream = () => {
                reader.read().then(({done, value}) => {
                    if (done) return;

                    setLoading(false);
                    setTextFlowing(true);

                    const chunk = decoder.decode(value, {stream: true});

                    chunk.split("\n").forEach((line) => {
                        if (line.startsWith("data: ")) {
                            const json = JSON.parse(line.substring(6));

                            if (json !== '') {

                                setResponses((prevResponses) => {
                                    const newResponses = [...prevResponses];
                                    newResponses[responseIndex] += json;
                                    setTokensOut(prevCount => prevCount + 1);

                                    return newResponses;
                                });

                                // Sroll inner container to bottom
                                scrollToBottom();

                            }

                        }
                        if (line.startsWith("complete: ")) {
                            //console.log(line.substring(10));
                            const json = JSON.parse(line.substring(10));
                            //console.log('json', json);


                            //console.log('answer', json.content[0].text.value);

                            // Save to messages array
                            messages.push({role: "assistant", content: json.content[0].text.value});

                            //console.log(messages);

                            if (json !== '') {
                                if(!threadId) {
                                    saveThread(json.thread_id);
                                    //console.log('Thread ID:', json.thread_id);
                                }
                            }

                            // Save question answer to local storage for thread history
                            // add it to existing local storage object
                            let obj = JSON.parse(localStorage.getItem('webien-ai-thread'));
                            obj.messages = messages;
                            localStorage.setItem('webien-ai-thread', JSON.stringify(obj));


                            setTextFlowing(false);


                        }

                    });

                    readStream();
                });


            };


            readStream();
        } catch (error) {
            console.error("Error fetching response:", error);
        }
    };

    return (
        <div>
            <button className={`openChat ${chatOpen ? "hide" : ""}`} onClick={() => openChat()}>
                <i className="icon icon-chat2"></i>
            </button>

            <div className={`chat ${chatOpen ? "active" : ""} ${chatStarted ? "started" : ""} ${messages.length ? "has-thread" : ""}`}>

                <div className="header">
                    {(() => {
                        if (!webienAi.showInfo) return null;

                        return (
                            <div className="info">
                                <div className="spend">
                                    <div className="txt"><b>{getSpend()}:-</b> Tokens: {formatNumber(tokensIn)} in
                                        | {formatNumber(tokensOut)} ut</div>
                                </div>
                                <div className="meta">
                                    <span><b>Assistent:</b> {webienAi.assistant.id}</span>
                                    <span><b>Vector:</b> {webienAi.assistant.vector_store_id}</span>
                                    <span><b>Thread:</b> {threadId}</span>
                                </div>
                                <div className="buttons">
                                    <button className="btn reset-thread" onClick={() => {
                                        resetThread();
                                    }}>Rensa historik</button>
                                </div>
                            </div>
                        );
                    })()}


                    <button className="closeChat" onClick={() => closeChat()}>
                        <i className="icon icon-close"></i>
                    </button>
                </div>


                <div className="conversation">
                    <div className="assistant first-msg">
                        <div className="avatar"><i className="icon icon-assistant"></i></div>
                        <div className="msg" dangerouslySetInnerHTML={{__html: marked(firstMsg)}}/>
                    </div>

                    {messages.map((msg, index) => {
                        if (msg.role === "assistant") {
                            return (
                                <div className="assistant" key={index}>
                                    <div className="avatar">
                                        <i className="icon icon-assistant"></i>
                                    </div>
                                    <div
                                        className="msg"
                                        dangerouslySetInnerHTML={{ __html: marked(msg.content) }}
                                    />
                                </div>
                            );
                        } else if (msg.role === "user") {
                            return (
                                <div
                                    className="user"
                                    key={index}
                                    dangerouslySetInnerHTML={{ __html: msg.content }}
                                />
                            );
                        } else {
                            return null;
                        }
                    })}


                    {(() => {
                        const lastResponse = responses[responses.length - 1];
                        if (!lastResponse || !textFlowing) return null;

                        return (
                            <div className="assistant lastResponse">
                                <div className="avatar"><i className="icon icon-assistant"></i></div>
                                <div className="msg" dangerouslySetInnerHTML={{ __html: marked(lastResponse) }}/>
                            </div>
                        );
                    })()}


                    {(() => {
                        if (!loading) return null;

                        return (
                            <div className="assistant loading">
                                <div className="avatar"><i className="icon icon-assistant"></i></div>
                                <div className="loader">
                                    <Loader/>
                                </div>
                            </div>
                        );
                    })()}

                </div>


                <div className="input-form">
                    <input
                        type="text"
                        value={message}
                        onKeyDown={(e) => {checkMessage(e)}}
                        onChange={(e) => setMessage(e.target.value)}
                        placeholder="Skriv din fråga här..."
                    />
                    <button className="submit" onClick={sendMessageToAI}><i className="icon icon-up"></i></button>
                    <button className="reset-thread" onClick={resetThread}>Rensa historik</button>

                </div>

            </div>
        </div>


    );
};

if (document.querySelectorAll(".webien-ai")) {
    document.querySelectorAll(".webien-ai").forEach((el) => {
        const root = createRoot(el);
        root.render(<Chat />);
    });
}

export default Chat;