import {
    EventMessage,
    EventType,
    PingMessage,
    PongMessage,
    PongMessageKindEnum,
    StatsMessage,
    StatusApi,
    SubscribeMessage, SubscribeMessageKindEnum,
    TaskStatusResponse,
    UserWalletBalance,
    UserWalletBalanceResponse,
    WalletApi
} from "@/api_fsb";
import Footer from "@/components/Footer";
import { useAppDispatch } from "@/hooks";
import { bpid, routeBasename, tagManager } from "@/lib/utils";
import { setAssignmentID, setProductUserID, setTurkSubmitTo } from "@/models/appSlice";
import { addEvent } from "@/models/grlEventsSlice";
import { addStatsData } from "@/models/grlStatsSlice";
import Home from "@/pages/Home";
import Preview from "@/pages/Preview";
import Result from "@/pages/Result";
import Work from "@/pages/Work";
import { BrowserRouter, Outlet, Route, Routes, useSearchParams } from "react-router-dom";
import useWebSocket from 'react-use-websocket';
import NewsTicker from "./components/EventMarquee";

import { useEffect } from "react";

import Wallet from "@/components/Wallet";
import "@/index.css";
import { setTaskStatus, setUserWalletBalance } from "@/models/appSlice";
import { Profiling } from "./components/Profiling";

type Message = PingMessage | PongMessage | SubscribeMessage | EventMessage | StatsMessage;

function isStatsMessage(msg: Message): msg is StatsMessage {
    return msg.kind === 'stats';
}

function isEventMessage(msg: Message): msg is EventMessage {
    return msg.kind === 'event';
}

function isPingMessage(msg: Message): msg is PingMessage {
    return msg.kind === 'ping';
}

function QueryParamProcessor() {
    const dispatch = useAppDispatch()
    const [searchParams] = useSearchParams();

    useEffect(() => {
        const worker_id = searchParams.get('workerId');
        const assignment_id = searchParams.get('assignmentId');
        const tsid = searchParams.get('tsid');
        const turkSubmitTo = searchParams.get('turkSubmitTo');

        if (turkSubmitTo) {
            dispatch(setTurkSubmitTo(turkSubmitTo))
        }

        if (worker_id) {
            dispatch(setProductUserID(worker_id))

            new WalletApi().getUserWalletBalanceProductIdWalletGet(
                bpid, // productId
                worker_id, // bpuid
            ).then(res => {
                const response = res.data as UserWalletBalanceResponse;
                const balance = response.wallet as UserWalletBalance;
                dispatch(setUserWalletBalance(balance));
            });
        }

        if (assignment_id) {
            dispatch(setAssignmentID(assignment_id))
        }

        if (tsid) {
            new StatusApi().getTaskStatusProductIdStatusTsidGet(
                bpid, // productId
                tsid).then(res => {
                    const response: TaskStatusResponse = res.data;
                    dispatch(setTaskStatus(response))
                }).catch((error) => {
                    console.error("Error fetching task status:", error);
                });
        }

    }, [searchParams]);

    return <Outlet />;
}

const Layout = () => {
    return (
        <div className="flex flex-col min-h-screen">
            <header className="bg-amber-400 text-amber-950 py-2 text-center">
                <a href="https://www.reddit.com/r/Marketresearch/comments/1s2tl0o/open_letter_to_cint_supplier_quality_issues/" target="_blank">
                    <h4 className="text-[12px]">
                        Letter to Cint: supplier quality issues, and malware-linked panels.
                    </h4>
                </a>
            </header>

            <main className="flex flex-1 bg-zinc-200">
                <div className="flex flex-col items-center justify-center flex-1">
                    <div className="
                    w-full max-w-full 
                    p-2 bg-white shadow-lg 
                    text-center space-y-4
                    md:max-w-5/8  md:rounded-lg
                    rounded-none 
                    ">
                        <Wallet />
                        <Profiling />
                        <Outlet />
                    </div>
                </div>
            </main >

            <footer className="bg-slate-700 text-zinc-200 p-2 text-center font-mono">
                <NewsTicker />
                <Footer />
            </footer>

        </div >
    );
};

function JBApp() {
    const dispatch = useAppDispatch()

    const { sendJsonMessage, lastMessage } = useWebSocket(
        "wss://fsb.generalresearch.com/ws/events/", {
        onOpen: () => {
            const subscribe: SubscribeMessage = {
                "kind": SubscribeMessageKindEnum.Subscribe,
                "product_id": bpid
            }
            sendJsonMessage(subscribe)
        }
    }
    );

    useEffect(() => {
        if (lastMessage !== null) {
            let msg: Message = JSON.parse(lastMessage.data);

            if (isStatsMessage(msg)) {
                dispatch(addStatsData(msg.data))

            } else if (isEventMessage(msg)) {
                // For simplicity, we just log the event messages here.
                // You can extend this to update the UI or trigger notifications as needed.

                switch (msg.data.event_type) {
                    case EventType.TaskEnter:
                    case EventType.TaskFinish:
                    case EventType.UserCreated:
                        dispatch(addEvent(msg.data));
                        break

                    default:
                        // do nothing for now
                        break;
                }

            } else if (isPingMessage(msg)) {
                const pong: PongMessage = {
                    "kind": PongMessageKindEnum.Pong,
                }
                sendJsonMessage(pong)
            }
        }
    }, [lastMessage]);

    useEffect(() => {
        if (!tagManager) return;

        var _mtm = window._mtm = window._mtm || [];
        _mtm.push({ 'mtm.startTime': (new Date().getTime()), 'event': 'mtm.Start' });
        var d = document, g = d.createElement('script'), s = d.getElementsByTagName('script')[0];
        g.async = true;
        g.src = tagManager;
        if (s.parentNode) {
            s.parentNode.insertBefore(g, s);
        }
    }, [tagManager])

    return (
        <BrowserRouter basename={routeBasename}>
            <Routes>
                <Route element={<QueryParamProcessor />}>
                    <Route element={<Layout />}>
                        <Route path="/" element={<Home />} />
                        <Route path="/preview/" element={<Preview />} />
                        <Route path="/work/" element={<Work />} />
                        <Route path="/result/" element={<Result />} />
                    </Route>
                </Route>
            </Routes>
        </BrowserRouter>
    )
}

export default JBApp;