import { Combobox, Transition } from "@headlessui/react";
import { CodeEditor } from "@/components/CodeEditor";
import { Skeleton } from "@/components/Skeleton";
import SkeletonLoader from "@/components/Skeleton/Skeleton";
import { AuthContext, tokenExpireError } from "@/context/Auth";
import { GlobalContext, showToast } from "@/context/Global";
import BaasSDK from "@/utils/BaasSDK";
import React from "react";
import { BsArrowReturnLeft } from "react-icons/bs";
import { ImSpinner10 } from "react-icons/im";
import { IoIosCopy } from "react-icons/io";
import { IoReturnDownBack } from "react-icons/io5";
import { useNavigate, useParams } from "react-router";
import { ChevronUpDownIcon } from "@heroicons/react/20/solid";
import WireframeSDK from "@/utils/WireframeSDK";
import { MdCancel } from "react-icons/md";

let baasSdk = new BaasSDK();
let wSDk = new WireframeSDK();

const GenerateQuery = () => {
  const { dispatch } = React.useContext(AuthContext);
  const { state: globalState, dispatch: globalDispatch } =
    React.useContext(GlobalContext);
  const [instructions, setInstructions] = React.useState("");
  const [isLoadingBtn, setIsLoadingBtn] = React.useState(false);
  const [defaultSchema, setDefaultSchema] = React.useState("");
  const [generatedSchema, setGeneratedSchema] = React.useState("");
  const [isLoadingList, setIsLoadingList] = React.useState(true);
  const [isLoadingSchema, setIsLoadingSchema] = React.useState(true);
  const [projects, setProjects] = React.useState([]);
  const [searchTerm, setSearchTerm] = React.useState("");
  const [activeTab, setActiveTab] = React.useState("");
  const [cursorPosition, setCursorPosition] = React.useState({
    line: 1,
    col: 0,
  });
  const instructionsRef = React.useRef(null);
  const { query } = useParams();
  const navigate = useNavigate();
  const { path } = globalState;

  React.useEffect(() => {
    (async function () {
      try {
        baasSdk.setTable("projects");
        const result = await baasSdk.callRestAPI(
          { direction: "DESC", limit: 1000 },
          "GETALL"
        );
        if (!result.error) {
          const { list } = result;
          setProjects(list);
          if (
            list?.length &&
            query === "project_name" &&
            path === "generate-query"
          ) {
            navigate(`/admin/generate-query/${list[0]?.project_id}`);
          }
        }
      } catch (error) {
        showToast(globalDispatch, error.message, 2000, "error");
        tokenExpireError(dispatch, error.message);
      } finally {
        setIsLoadingList(false);
      }
    })();
  }, []);

  React.useEffect(() => {
    (async function () {
      try {
        baasSdk.setTable("projects");
        const result = await baasSdk.getSchemaTables(activeTab, "GET");
        if (!result.error) {
          const response = JSON.stringify(result);
          setDefaultSchema(response);
          setGeneratedSchema(response);
        }
      } catch (error) {
        showToast(globalDispatch, error.message, 2000, "error");
        tokenExpireError(dispatch, error.message);
      } finally {
        setIsLoadingSchema(false);
      }
    })();
  }, [activeTab]);

  React.useEffect(() => {
    globalDispatch({
      type: "SETPATH",
      payload: {
        path: "generate-query",
      },
    });
    setActiveTab(query);
  }, [query, isLoadingList]);

  React.useEffect(() => {
    (() => {
      if (!isLoadingList && projects.length) {
        instructionsRef.current.focus();
        setIsLoadingSchema(true);
        setInstructions("");
      }
    })();
  }, [activeTab, isLoadingList]);

  const handleOnChange = (event) => {
    setInstructions(event.target.value);
    const { value, selectionStart, selectionEnd } = event.target;
    const lines = value.substr(0, selectionStart).split("\n");
    const line = lines.length;
    const col = lines[lines.length - 1].length;

    if (selectionEnd === selectionStart && value[selectionStart] === "\n") {
      setCursorPosition({ line: line + 1, col: 0 });
    } else {
      setCursorPosition({ line, col });
    }
    requestAnimationFrame(() => {
      const lineHeight = parseFloat(
        getComputedStyle(instructionsRef.current).lineHeight
      );
      instructionsRef.current.scrollTop =
        (cursorPosition.line - 1) * lineHeight;
    });
  };

  const handleKeyDown = (event) => {
    if (!event.shiftKey && event.key === "Enter") {
      event.preventDefault();
      handleChangeQuery(event);
      return;
    }
    if (event.shiftKey && event.key === "Enter") {
      event.preventDefault();
      const newInstructions = `${instructions.substring(
        0,
        event.target.selectionStart
      )}\n${instructions.substring(event.target.selectionStart)}`;
      setInstructions(newInstructions);
      setCursorPosition({ line: cursorPosition.line + 1, col: 0 });
    }
  };

  const handleChangeQuery = async (event, from) => {
    if (event.key === "Enter" || from === "onClick") {
      setIsLoadingBtn(true);
      const slug = projects.find(
        (item) => item?.project_id === activeTab
      )?.slug;

      try {
        const userPrompt = `${generatedSchema} Given the above schema. provide an sql query based on the instructions delimited by ### Respond with only valid SQL query and prefix database tables with ${slug}_   ### ${instructions} ###`;
        let prompt =
          generatedSchema === defaultSchema
            ? [
                {
                  role: "system",
                  content:
                    "You are an expert database engineer. Do not explain and respond with only valid SQL query.",
                },
                {
                  role: "user",
                  content: userPrompt,
                },
              ]
            : [
                {
                  role: "system",
                  content:
                    "You are an expert database engineer. Do not explain and respond with only valid SQL query.",
                },
                { role: "assistant", content: generatedSchema },
                {
                  role: "user",
                  content: userPrompt,
                },
              ];
        const result = await wSDk.askGptCustom(prompt);
        if (!result.error) {
          const response = result.message?.message?.content;
          setGeneratedSchema(response);
        }
      } catch (error) {
        showToast(globalDispatch, error?.message, 2000, "error");
        tokenExpireError(dispatch, error.message);
      }
      setIsLoadingBtn(false);
    }
  };

  const backToDefault = () => {
    instructionsRef.current.focus();
    const defaultQueries = defaultSchema;
    setGeneratedSchema(defaultQueries);
  };

  const copyToClipboard = (queryToCopy) => {
    try {
      navigator.clipboard.writeText(queryToCopy);
      showToast(globalDispatch, "Copied");
    } catch (error) {
      showToast(globalDispatch, "Error copying to clipboard", 2000, "error");
      tokenExpireError(dispatch, error.message);
    }
  };

  const filteredProjects =
    searchTerm === ""
      ? projects
      : projects.filter((project) =>
          project.name
            .toLowerCase()
            .replace(/\s+/g, "")
            .includes(searchTerm.toLowerCase().replace(/\s+/g, ""))
        );

  return (
    <>
      {
        <div className="min-h-screen px-8 py-3">
          <h1 className="my-3 gap-5 pb-2 text-xl">
            <span>Generate SQL Queries</span>
          </h1>
          {/* <div className=" flex items-center justify-between"> */}
          <div className="relative mb-3 w-2/12">
            <Combobox value={activeTab} onChange={setActiveTab}>
              <div className="relative mt-1">
                <Combobox.Input
                  placeholder="Type to search"
                  className=" min-w-2/5 w-full rounded-md border border-[#E0E0E0] py-2 pl-3 pr-10 text-base  leading-5 text-gray-900 focus:ring-0"
                  onChange={(event) => setSearchTerm(event.target.value)}
                />
                <Combobox.Button className="absolute inset-y-0 right-0 flex items-center pr-2">
                  <ChevronUpDownIcon
                    className="h-5 w-5 text-gray-500"
                    aria-hidden="true"
                  />
                </Combobox.Button>
              </div>
              <Transition
                leave="transition ease-in duration-100"
                leaveFrom="opacity-100"
                leaveTo="opacity-0"
                afterLeave={() => setSearchTerm("")}
              />

              <Combobox.Options className="max-w-1/2 absolute z-20 mt-1 max-h-60 overflow-auto rounded-md bg-white text-base shadow-lg ring-1 ring-black/5">
                {filteredProjects.length === 0 && query !== "" ? (
                  <div className="w-50 select-none px-4 py-2 text-gray-700">
                    Nothing found.
                  </div>
                ) : (
                  filteredProjects.map((item) => (
                    <Combobox.Option
                      className={({ active }) =>
                        `cursor-default select-none px-5 py-2 ${
                          active ? "bg-gray-200" : "text-gray-900"
                        }`
                      }
                      key={item?.id}
                      value={item?.project_id}
                      onClick={() =>
                        navigate(`/admin/generate-query/${item.project_id}`)
                      }
                    >
                      <Combobox.Button>{item?.name}</Combobox.Button>
                    </Combobox.Option>
                  ))
                )}
              </Combobox.Options>
            </Combobox>
          </div>
          {isLoadingList ? (
            <div className="mb-3 h-14 w-full animate-pulse rounded-md bg-gray-300"></div>
          ) : (
            <div className="hover-container relative z-10 flex w-full items-center justify-center pb-2">
              <textarea
                placeholder="Make sql from database tables"
                onKeyDown={(event) => handleKeyDown(event)}
                value={instructions}
                className="scrollbar-hide flex-1 resize-none overflow-auto whitespace-pre-wrap rounded-lg py-5 pl-6 pr-28"
                ref={instructionsRef}
                onChange={(event) => handleOnChange(event)}
                rows={1}
                maxLength={300}
              />

              <div className="absolute bottom-0 right-0 flex py-2">
                <button
                  onClick={() => {
                    setInstructions("");
                  }}
                  className={
                    instructions?.length ? "visible-btn hidden" : "hidden"
                  }
                >
                  <MdCancel
                    style={{ fontSize: 27 }}
                    className=" font-bold text-gray-700"
                  />
                </button>
                <button
                  onClick={(event) =>
                    !isLoadingBtn && handleChangeQuery(event, "onClick")
                  }
                  className=" px-4 py-1.5 text-white shadow-sm"
                >
                  <span className="block p-3">
                    {isLoadingBtn ? (
                      <ImSpinner10
                        style={{ fontSize: 27 }}
                        className="animate-spin font-bold text-gray-700"
                      />
                    ) : (
                      <BsArrowReturnLeft
                        style={{ fontSize: 26 }}
                        className="font-bold text-gray-700"
                      />
                    )}
                  </span>
                </button>
              </div>
            </div>
          )}

          {/* </div> */}

          <div className="flex pt-2">
            <div className={`inset-0 grid h-auto w-full rounded-lg`}>
              {
                <div className="text-medium w-ful scrollbar-hide relative mb-5 flex h-full min-h-full flex-1 resize-none flex-col items-center justify-center overflow-scroll rounded-xl border border-[#a8a8a8] bg-gray-700 p-5 text-[#525252] shadow-md">
                  {!isLoadingBtn &&
                  generatedSchema?.length &&
                  !(generatedSchema === defaultSchema) ? (
                    <button
                      onClick={() => copyToClipboard(generatedSchema)}
                      className="absolute right-0 top-0 z-10 flex cursor-pointer items-center rounded-lg rounded-br-none rounded-tl-none border border-[#a8a8a8] bg-gray-200 px-2 py-1 shadow-md "
                    >
                      <IoIosCopy style={{ fontSize: 18 }} />
                      &nbsp;Copy
                    </button>
                  ) : (
                    <></>
                  )}
                  <div
                    className={`absolute left-0 top-0 z-10 ${
                      ((!isLoadingBtn && generatedSchema === defaultSchema) ||
                        isLoadingBtn) &&
                      "hidden"
                    }`}
                  >
                    <button
                      onClick={backToDefault}
                      className="inline-flex gap-2 rounded-lg rounded-bl-none rounded-tr-none border border-[#a8a8a8] bg-blue-100 px-4 py-1 font-semibold shadow-md hover:bg-blue-200"
                    >
                      Original{" "}
                      <IoReturnDownBack
                        style={{ fontSize: 20, fontWeight: "bolder" }}
                      />
                    </button>
                  </div>
                  <div className="scrollbar-hide w-full py-3 pl-6 pr-7">
                    <CodeEditor
                      fontSize={15}
                      className={`scrollbar-hide rounded-lg`}
                      code={
                        generatedSchema === defaultSchema ? "" : generatedSchema
                      }
                      language={`sql`}
                      onChange={(value) => setGeneratedSchema(value)}
                      maxHeight="55vh"
                    />
                  </div>
                </div>
              }
            </div>
          </div>
        </div>
      }
    </>
  );
};

export default GenerateQuery;
