import { CodeBracketIcon, EyeIcon } from "@heroicons/react/20/solid";
import { ReactIcon } from "@/assets/svgs";
import { BsArrowReturnLeft } from "react-icons/bs";
import { ImSpinner10 } from "react-icons/im";
import { CodeEditor } from "@/components/CodeEditor";
import { DropdownOption, DropdownOptions } from "@/components/DropdownOptions";
import SkeletonLoader from "@/components/Skeleton/Skeleton";
import { GlobalContext, showToast } from "@/context/Global";
import WireframeSDK from "@/utils/WireframeSDK";
import React, { useMemo } from "react";
import { IoIosArrowDown, IoIosCopy } from "react-icons/io";
import { useNavigate, useParams } from "react-router";
import { FaHtml5 } from "react-icons/fa";
import { TbFileTypeJsx } from "react-icons/tb";
import { IoReturnDownBack } from "react-icons/io5";
import { AuthContext, tokenExpireError } from "@/context/Auth";
import { MdCancel } from "react-icons/md";

const MyComponent = ({ code }) => {
  return <div dangerouslySetInnerHTML={{ __html: code }} />;
};

let wSDk = new WireframeSDK();

const GenerateUI = () => {
  const { dispatch } = React.useContext(AuthContext);
  const { dispatch: globalDispatch } = React.useContext(GlobalContext);
  const [showCode, setShowCode] = React.useState(false);
  const [instructions, setInstructions] = React.useState("");
  const [htmlCode, setHtmlCode] = React.useState("");
  const [generatedHtml, setGeneratedHtml] = React.useState("");
  const [generatedJSX, setGeneratedJSX] = React.useState("");
  const [typeIndex, setTypeIndex] = React.useState(0);
  const [isLoadingBtn, setIsLoadingBtn] = React.useState(false);
  const [activeTab, setActiveTab] = React.useState({
    name: "Button",
    tabId: "button",
  });
  const [cursorPosition, setCursorPosition] = React.useState({
    line: 1,
    col: 0,
  });
  const instructionsRef = React.useRef(null);
  const { component } = useParams();
  const navigate = useNavigate();

  const codeData = useMemo(
    () => [
      {
        name: "Button",
        code: `
          <button class="inline-flex items-center px-4 py-2 bg-indigo-500 hover:bg-indigo-600 text-white text-sm font-medium rounded-md">
            <svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
              <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 10h10a8 8 0 018 8v2M3 10l6 6m-6-6l6-6" />
            </svg>
            I am a button
          </button>
        `,
        tabId: "button",
      },
      {
        name: "Toggle",
        code: `
          <label for="toggleTwo" class="flex items-center cursor-pointer select-none text-dark dark:text-white">
            <div class="relative">
              <input type="checkbox" id="toggleTwo" class="peer sr-only"/>
              <div class="block h-8 rounded-full bg-dark-2 bg-gray-3 w-14 bg-white border border-[#8d8d8d]"></div>
              <div class="absolute w-6 h-6 transition bg-[#8d8d8d] rounded-full dot dark:bg-dark-4 left-1 top-1 peer-checked:translate-x-full peer-checked:bg-primaryBlue">
                <div></div>
              </div>
            </div>
          </label>
        `,
        tabId: "toggle",
      },
      // {
      //   name: "Empty",
      //   code: `<div class="border border-gray-50 p-2"> </div>
      //   `,
      //   tabId: "empty",
      // },
      {
        name: "Custom",
        code: ``,
        tabId: "custom",
      },
      {
        name: "Form",
        code: `
          <form action="#" class="space-y-5 w-full">
            <h4 class="text-2xl font-semibold">Contact Us</h4>
            <div>
              <label for="name" class="block mb-1 text-sm font-medium text-gray-700">Full Name</label>
              <input type="text" id="name" class="shadow-sm bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5" placeholder="Enter Your Name" required>
            </div>
            <div>
              <label for="email" class="block mb-1 text-sm font-medium text-gray-700">Email Address</label>
              <input type="email" id="email" class="shadow-sm bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5" placeholder="name@flowbite.com" required>
            </div>
            <div>
              <label for="message" class="block mb-1 text-sm font-medium text-gray-700">Message</label>
              <textarea type="email" id="email" class="shadow-sm bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-primary-500 focus:border-primary-500 block w-full p-2.5 resize-none" placeholder="name@flowbite.com" required></textarea>
            </div>
            <div class="text-center">
              <button type="submit" class="py-2 px-5 text-sm font-medium text-center text-white rounded-full bg-blue-600 sm:w-fit hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-primary-300 ">Send message</button>
            </div>
          </form>
        `,
        tabId: "form",
      },
      {
        name: "Avatar",
        code: `
          <div class="text-center">
            <img
              src="https://tecdn.b-cdn.net/img/new/avatars/2.webp"
              class="mx-auto mb-4 w-32 rounded-lg"
              alt="Avatar" 
            />
            <h5 class="mb-2 text-xl font-medium leading-tight">John Doe</h5>
            <p class="text-neutral-500 dark:text-neutral-400">Web designer</p>
          </div>   
        `,
        tabId: "avatar",
      },
      {
        name: "Breadcrumb",
        code: `
          <nav class="flex" aria-label="Breadcrumb">
            <ol class="inline-flex items-center space-x-1 md:space-x-2 rtl:space-x-reverse">
              <li class="inline-flex items-center">
                <a href="#" class="inline-flex items-center text-sm font-medium text-gray-800 hover:text-blue-600">
                  Home
                </a>
              </li>
              <li>
                <div class="flex items-center">
                  <svg class="rtl:rotate-180 w-3 h-3 text-gray-400 mx-1" aria-hidden="true" fill="none" viewBox="0 0 6 10">
                    <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 9 4-4-4-4"/>
                  </svg>
                  <a href="#" class="ms-1 text-sm font-medium text-gray-800 hover:text-blue-600 md:ms-2">Projects</a>
                </div>
              </li>
              <li aria-current="page">
                <div class="flex items-center">
                  <svg class="rtl:rotate-180 w-3 h-3 text-gray-400 mx-1" aria-hidden="true" fill="none" viewBox="0 0 6 10">
                    <path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m1 9 4-4-4-4"/>
                  </svg>
                  <span class="ms-1 text-sm font-medium text-gray-500 md:ms-2">Flowbite</span>
                </div>
              </li>
            </ol>
          </nav> 
        `,
        tabId: "breadcrumb",
      },
      {
        name: "Card",
        code: `
          <div class="block rounded-lg bg-white shadow-md">
            <a href="#!">
              <img
                class="rounded-t-lg"
                src="https://tecdn.b-cdn.net/img/new/standard/nature/184.jpg"
                alt=""
              />
            </a>
            <div class="p-4">
              <h5 class="mb-2 text-xl font-medium leading-tight text-gray-800">
                Card title
              </h5>
              <p class="mb-4 text-base text-gray-600">
                Some quick example text to build on the card title and make up the bulk of the card's content.
              </p>
              <button
                type="button"
                class="inline-block rounded bg-primary px-4 py-1.5 text-xs font-medium uppercase leading-normal text-white shadow-md transition duration-150 ease-in-out hover:bg-primary-600 focus:bg-primary-600 focus:outline-none focus:ring-0 active:bg-primary-700"
                data-te-ripple-init
                data-te-ripple-color="light"
              >
                Button
              </button>
            </div>
          </div>
        `,
        tabId: "card",
      },
    ],
    []
  );

  const codeType = useMemo(
    () => [
      {
        name: "Html",
        icon: <FaHtml5 style={{ fontSize: 18 }} />,
      },
      {
        name: "JSX",
        icon: <TbFileTypeJsx style={{ fontSize: 18 }} />,
      },
    ],
    []
  );

  React.useEffect(() => {
    globalDispatch({
      type: "SETPATH",
      payload: {
        path: "generate-ui",
      },
    });
    const newSelectedTab = codeData.find((item) => item.tabId == component);
    setActiveTab(newSelectedTab);
  }, [component]);

  React.useEffect(() => {
    (() => {
      const code = codeData?.find(
        (code) => code.tabId === activeTab.tabId
      )?.code;
      let jsxCode = code?.replace(/class/gi, "className");
      instructionsRef.current.focus();
      setHtmlCode(code);
      setGeneratedHtml(code);
      setGeneratedJSX(jsxCode);
      setInstructions("");
      setShowCode(false);
      if (activeTab.tabId == "custom") {
        setShowCode(true);
      }
    })();
  }, [activeTab]);

  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();
      handleChangeCode(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 });
    }
  };

  function replaceDelimitter(inputString) {
    let resultString = inputString?.replace(/##/g, "");
    resultString = resultString?.replace(/\$\$/g, "");
    return resultString;
  }

  const handleChangeCode = async (event, from) => {
    if (event.key === "Enter" || from === "onClick") {
      setIsLoadingBtn(true);
      setShowCode(false);
      // setGeneratedHtml("");
      // setGeneratedJSX("");
      try {
        const userPrompt = `modify the component delimited by ## according to the instruction delimited by $$. Transform the modified component to React JSX. Format response in JSON. example: {html: '', react: ''}
        ##
        ${generatedHtml}
        ##
        
        $$
        ${instructions}
        $$
        `;

        let prompt = [
          {
            role: "system",
            content:
              "You are an expert frontend engineer. strictly use html, tailwind css, jsx. Do not explain and do not return delimeter in response.",
          },
          {
            role: "user",
            content: userPrompt,
          },
        ];
        const result = await wSDk.askGptCustom(prompt);
        if (!result.error) {
          const response = JSON.parse(result.message?.message?.content);
          if (response?.html?.length && response?.react) {
            setGeneratedHtml(replaceDelimitter(response?.html));
            setGeneratedJSX(replaceDelimitter(response?.react));
          } else {
            showToast(
              globalDispatch,
              "Operation not successful! Try again.",
              2000,
              "error"
            );
          }
        }
      } catch (error) {
        showToast(globalDispatch, error?.message, 2000, "error");
        tokenExpireError(dispatch, error.message);
      }
      setIsLoadingBtn(false);
      // setInstructions("");
    }
  };

  const backToDefault = () => {
    const code = codeData?.find((code) => code.tabId === activeTab.tabId)?.code;
    let jsxCode = code?.replace(/class/gi, "className");
    instructionsRef.current.focus();
    setHtmlCode(code);
    setGeneratedHtml(code);
    setGeneratedJSX(jsxCode);
  };

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

  return (
    <div className="min-h-screen px-8 py-3">
      <h1 className="my-3 flex items-center justify-between gap-5 text-xl ">
        <span>Generate HTML/Tailwind Components</span>
        <span className="border-b-2 border-[#E5E5E5] text-lg">
          {activeTab?.name}
        </span>
      </h1>
      <div className="flex items-center justify-between">
        <div>
          <DropdownOptions
            style={{ justifyContent: "flex-start" }}
            icon={
              <div className="my-2 flex items-center gap-3 rounded-md border border-[#E0E0E0] px-2.5 py-1">
                <IoIosArrowDown />
                Component
              </div>
            }
            className="w-full"
            iconWrapperClass="text-[14px] font-medium text-left"
            childrenWrapperClass="left-auto right-auto max-h-[40vh] overflow-scroll"
          >
            {codeData.map((item, index) => (
              <DropdownOption
                key={index}
                icon={<ReactIcon />}
                name={item.name}
                onClick={() => navigate(`/admin/generate-ui/${item.tabId}`)}
              />
            ))}
          </DropdownOptions>
        </div>
        <div>
          <button onClick={() => setShowCode((prev) => !prev)}>
            {!showCode ? (
              <div className="mr[-100px] my-2 flex items-center gap-3 rounded-md border border-[#E0E0E0] px-5 py-1">
                <CodeBracketIcon style={{ color: "3f4f4f4" }} width={20} />
                Code
              </div>
            ) : (
              <div className="mr[-100px] my-2 flex items-center gap-3 rounded-md border border-[#E0E0E0] px-2.5 py-1">
                <EyeIcon width={20} />
                Preview
              </div>
            )}
          </button>
        </div>
      </div>
      <div className="hover-container relative z-10 mx-auto mb-2 flex w-full items-center justify-center">
        <textarea
          placeholder="Make the text larger, or change colors"
          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">
          <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 && handleChangeCode(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 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] p-5 text-[#525252] shadow-md ${
              showCode ? "bg-gray-700" : ""
            }`}
          >
            <div
              className={`absolute left-0 top-0 z-10 ${
                ((!isLoadingBtn && generatedHtml === htmlCode) ||
                  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>
            {showCode ? (
              <div 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 py-0.5 pr-2 shadow-md ">
                <DropdownOptions
                  style={{ justifyContent: "flex-start" }}
                  icon={
                    <div className="flex items-center gap-3 border-r-2 border-gray-600 px-2.5 py-0.5">
                      <IoIosArrowDown
                        style={{ fontSize: 20, fontWeight: "bolder" }}
                      />
                      {codeType[typeIndex].name}
                    </div>
                  }
                  className="w-full"
                  iconWrapperClass="text-[14px] font-medium text-left"
                  childrenWrapperClass="left-auto right-auto"
                >
                  {codeType.map((item, index) => (
                    <DropdownOption
                      key={item.name}
                      icon={item.icon}
                      name={item.name}
                      onClick={() => setTypeIndex(index)}
                    />
                  ))}
                </DropdownOptions>
                <div className="pl-2.5">
                  <IoIosCopy
                    style={{ fontSize: 18 }}
                    onClick={() =>
                      copyToClipboard(typeIndex ? generatedJSX : generatedHtml)
                    }
                  />
                </div>
              </div>
            ) : (
              <></>
            )}

            {isLoadingBtn ? (
              <SkeletonLoader
                className="rounded-md bg-white"
                count={3}
                counts={[4, 1, 1]}
              />
            ) : (
              <>
                {showCode ? (
                  <div className="scrollbar-hide w-full py-3 pl-6 pr-7">
                    <CodeEditor
                      fontSize={15}
                      className={`scrollbar-hide rounded-lg`}
                      code={typeIndex ? generatedJSX : generatedHtml}
                      language={`javascript`}
                      onChange={(value) =>
                        typeIndex
                          ? setGeneratedJSX(value)
                          : setGeneratedHtml(value)
                      }
                      maxHeight="60vh"
                      // readOnly={true}
                    />
                  </div>
                ) : (
                  <div className=" flex min-h-[45vh] items-center justify-center self-center rounded-xl">
                    <MyComponent
                      code={
                        typeIndex
                          ? generatedJSX?.replace(/className/gi, "class")
                          : generatedHtml
                      }
                    />
                  </div>
                )}
              </>
            )}
          </div>
        </div>
      </div>
    </div>
  );
};

export default GenerateUI;
