import { useQuery, useQueryClient } from "@tanstack/react-query";
import spinner from "@/assets/triangles.svg";
import { useEffect, useRef, useState } from "react";
import useLocalState from "@/state/state";
import type { PostID } from "@/types/trill";
import type { Ship } from "@/types/urbit";

function PostData(props: {
  host: Ship;
  id: PostID;
  rter?: Ship;
  rtat?: number;
  rtid?: PostID;
  nest?: number; // nested quotes
  className?: string;
}) {
  const { api } = useLocalState();
  const { host, id, nest } = props;
  const [enest, setEnest] = useState(nest);
  useEffect(() => {
    setEnest(nest);
  }, [nest]);

  return function (Component: React.ElementType) {
    // const [showNested, setShowNested] = useState(nest <= 3);
    const handleShowNested = (e: React.MouseEvent) => {
      e.stopPropagation();
      setEnest(enest! - 3);
    };
    const [dead, setDead] = useState(false);
    const [denied, setDenied] = useState(false);
    const { isLoading, isError, data, refetch } = useQuery({
      queryKey: ["trill-thread", host, id],
      queryFn: fetchNode,
    });
    const queryClient = useQueryClient();
    const dataRef = useRef(data);
    useEffect(() => {
      dataRef.current = data;
    }, [data]);

    async function fetchNode(): Promise<any> {
      const res = await api!.scryPost(host, id, null, null);
      if ("fpost" in res) return res;
      else {
        const existing = queryClient.getQueryData(["trill-thread", host, id]);
        const existingData = existing || data;
        if ("bugen" in res) {
          // we peek for the actual node
          peekTheNode();
          // if we have a cache we don't invalidate it
          if (existingData && "fpost" in existingData) return existingData;
          // if we don't have a cache then we show the loading screen
          else return res;
        }
        if ("no-node" in res) {
          if (existingData && "fpost" in existingData) return existingData;
          else return res;
        }
      }
    }
    function peekTheNode() {
      let timer;
      peekNode({ ship: host, id });
      timer = setTimeout(() => {
        const gotPost = dataRef.current && "fpost" in dataRef.current;
        setDead(!gotPost);
        // clearTimeout(timer);
      }, 10_000);
    }

    useEffect(() => {
      const path = `${host}/${id}`;
      if (path in peekedPosts) {
        queryClient.setQueryData(["trill-thread", host, id], {
          fpost: peekedPosts[path],
        });
      } else if (path in deniedPosts) {
        setDenied(true);
      }
    }, [peekedPosts]);
    useEffect(() => {
      const path = `${host}/${id}`;
      if (path in deniedPosts) setDenied(true);
    }, [deniedPosts]);

    useEffect(() => {
      const l = lastThread;
      if (l && l.thread == id) {
        queryClient.setQueryData(["trill-thread", host, id], { fpost: l });
      }
    }, [lastThread]);
    function retryPeek(e: React.MouseEvent) {
      e.stopPropagation();
      setDead(false);
      peekTheNode();
    }
    if (enest > 3)
      return (
        <div className={props.className}>
          <div className="lazy x-center not-found">
            <button className="x-center" onMouseUp={handleShowNested}>
              Load more
            </button>
          </div>
        </div>
      );
    else
      return data ? (
        dead ? (
          <div className={props.className}>
            <div className="no-response x-center not-found">
              <p>{host} did not respond</p>
              <button className="x-center" onMouseUp={retryPeek}>
                Try again
              </button>
            </div>
          </div>
        ) : denied ? (
          <div className={props.className}>
            <p className="x-center not-found">
              {host} denied you access to this post
            </p>
          </div>
        ) : "no-node" in data || "bucun" in data ? (
          <div className={props.className}>
            <p className="x-center not-found">Post not found</p>
          </div>
        ) : "bugen" in data ? (
          <div className={props.className}>
            <div className="x-center not-found">
              <p className="x-center">Post not found, requesting...</p>
              <img src={spinner} className="x-center s-100" alt="" />
            </div>
          </div>
        ) : "fpost" in data && data.fpost.contents === null ? (
          <div className={props.className}>
            <p className="x-center not-found">Post deleted</p>
          </div>
        ) : (
          <Component
            data={data.fpost}
            refetch={refetch}
            {...props}
            nest={enest}
          />
        )
      ) : // no data
      isLoading || isError ? (
        <div className={props.className}>
          <img className="x-center post-spinner" src={spinner} alt="" />
        </div>
      ) : (
        <div className={props.className}>
          <p>...</p>
        </div>
      );
  };
}
export default PostData;
