import { Textarea } from "../../tremor/Textarea";
import { Button } from "../../tremor/Button";
import { Text } from "../../tremor/Text";
import { Card } from "../../tremor/Card";
import { Icon } from "../../tremor/Icon";
import { useEffect, useMemo, useRef, useState } from "react";
import React from "react";
import { useBackend } from "../../layouts/Wrapper";
import remarkGfm from "remark-gfm";
import ReactMarkdown from "react-markdown";
import dayjs from "dayjs";
import relativeTime from "dayjs/plugin/relativeTime";
import { ErrorBoundary } from "react-error-boundary";
import {
  ArrowDownTrayIcon,
  ArrowRightIcon,
  DocumentChartBarIcon,
  HandThumbDownIcon as HandThumbDownOutlineIcon,
  HandThumbUpIcon as HandThumbUpOutlineIcon,
  PencilIcon,
  PhotoIcon,
} from "@heroicons/react/24/outline";
import {
  HandThumbDownIcon as HandThumbDownSolidIcon,
  HandThumbUpIcon as HandThumbUpSolidIcon,
} from "@heroicons/react/24/solid";
import ChartBase from "../Chart/ChartBase";
import { useDashboard } from "../../layouts/Dashboard/useDashboard";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuGroup,
  DropdownMenuIconWrapper,
  DropdownMenuItem,
  DropdownMenuLabel,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from "../../tremor/DropdownMenu";
import {
  Accordion,
  AccordionContent,
  AccordionItem,
  AccordionTrigger,
} from "../../tremor/Accordion";
import { Message } from "@onvo-ai/js";
import { useTheme } from "../../layouts/Dashboard/useTheme";
import { toast } from "sonner";
import { Popover, PopoverContent, PopoverTrigger } from "../../tremor/Popover";
import { SparklesIcon } from "@heroicons/react/20/solid";
import { ChartPlaceholder } from "../ChartLoader";
import { Widget } from "@onvo-ai/js";

dayjs.extend(relativeTime);



const VotePopover: React.FC<{ children: React.ReactNode, questionId: string, messageId: string, type: "up" | "down", onSubmit: (reason: string) => void }> = ({ children, questionId, messageId, type, onSubmit }) => {

  const { backend } = useBackend();
  const [reason, setReason] = useState("");
  const [open, setOpen] = useState(false);
  const [loading, setLoading] = useState(false);

  const handleVote = async () => {
    if (!backend) return;
    setLoading(true);
    await backend.question(questionId).voteMessage(messageId, type, reason);
    onSubmit(reason);
    setLoading(false);
    setOpen(false);
  }

  return <Popover open={open} onOpenChange={setOpen}>
    <PopoverTrigger asChild>
      {children}
    </PopoverTrigger>
    <PopoverContent className="!onvo-p-4">
      <Text>Why did you {type === "up" ? "like" : "dislike"} this message?</Text>
      <Textarea className="onvo-my-2" onChange={(e) => setReason(e.target.value)} placeholder="Explain why you voted"></Textarea>
      <Button className="onvo-w-full" onClick={handleVote} isLoading={loading}>Submit</Button>
    </PopoverContent>
  </Popover>
}


export const QuestionMessage: React.FC<{
  isLast?: boolean;
  questionLoading?: boolean;
  message: Message;
  onAdd: (widget: Widget, library?: boolean) => void;
  onEdit: (msg: string) => void;
  onReply: (msg: string) => void;
}> = ({
  isLast,
  questionLoading,
  message,
  onAdd,
  onEdit,
  onReply
}) => {
    const { adminMode, containerRef, backend } = useBackend();
    const { dashboard } = useDashboard();
    const theme = useTheme();

    const elementRef = useRef<any>(null);

    const [widget, setWidget] = useState<Widget>();
    const [cache, setCache] = useState<any>();

    const [vote, setVote] = useState<"up" | "down">();

    const [editing, setEditing] = useState(false);
    const [newMessage, setNewMessage] = useState("");

    const [explainingCode, setExplainingCode] = useState(false);
    const [explainedCode, setExplainedCode] = useState<string | null>(null);

    const { role, content, widget: widgetId } = message;

    const getWidget = async (id: string) => {
      let newWidget = await backend?.widgets.get(id);
      setWidget(newWidget);
      if (!newWidget || !newWidget.code || newWidget.code.trim() === "") return;
      let obj = await backend?.widget(id).cache();
      setCache(obj?.data);
    }

    useEffect(() => {
      if (!widgetId) return;
      getWidget(widgetId);
    }, [widgetId, isLast, questionLoading]);

    const explainCode = async () => {
      if (!widget || !backend) return;
      setExplainingCode(true);
      setExplainedCode(null);
      try {
        let result = await backend.widget(widget.id).annotateCode();
        setExplainedCode(result.insights);
      } catch (e: any) {
        toast.error("Failed to explain code: " + e.message);
      }
      setExplainingCode(false);
    };

    useEffect(() => {
      if (!message) return;
      setVote(message.vote || undefined);
    }, [message]);

    const onDownload = (format: "svg" | "png" | "csv" | "xlsx" | "jpeg") => {
      if (!backend) return;
      if (!widgetId) return;
      toast.promise(
        () => {
          return backend.widget(widgetId).export(format, theme);
        },
        {
          loading: `Exporting widget as ${format}...`,
          success: async (output: any) => {
            console.log("OUTPUT: ", output);
            try {
              // Get the file URL, replacing host.docker.internal with localhost if needed
              const fileUrl = output.url.replace("host.docker.internal", "localhost");

              // Create a link element
              const link = document.createElement('a');
              link.href = fileUrl;
              link.download = output.fileName || `export.${format}`; // Set the filename
              link.style.display = 'none';

              // Add to document, click and remove
              document.body.appendChild(link);
              link.click();

              // Clean up
              setTimeout(() => {
                document.body.removeChild(link);
              }, 100);
            } catch (error) {
              console.error('Download failed:', error);
              toast.error('Download failed. Please try again.');
            }

            return "Widget exported";
          },
          error: (error) => "Error exporting widget: " + error.message,
        }
      );
    };


    if (role === "user") {
      let text = content as string;
      return (
        <div className="onvo-w-full onvo-flex onvo-flex-col onvo-group onvo-animate-slideLeftAndFade">
          <div className={"onvo-question-message-user onvo-rounded-2xl onvo-py-3 onvo-px-4 onvo-bg-black/5 dark:onvo-bg-white/10 onvo-relative onvo-mb-3 onvo-flex onvo-flex-row onvo-items-start onvo-justify-start onvo-gap-3 onvo-self-end " + (editing ? "onvo-w-full" : "onvo-max-w-[80%]")}>
            <div className="onvo-w-full onvo-max-w-none">
              {editing ? (
                <Textarea
                  className="!onvo-text-[0.875rem] !onvo-outline-none focus:onvo-outline-none focus:onvo-border-transparent focus:onvo-ring-0 !onvo-p-0 !onvo-leading-[1.5142857rem] !onvo-bg-transparent !onvo-shadow-none onvo-border-none"
                  defaultValue={content as string}
                  onChange={(e) => setNewMessage(e.target.value)}
                />
              ) : (
                <ErrorBoundary fallbackRender={({ error }) => <Text>{text}</Text>}>
                  <ReactMarkdown
                    className="onvo-prose onvo-prose-slate onvo-prose-sm dark:onvo-prose-invert "
                    remarkPlugins={[remarkGfm]}
                  >
                    {text}
                  </ReactMarkdown>
                </ErrorBoundary>
              )}

              {editing ? (
                <div className="onvo-flex onvo-flex-row onvo-justify-end onvo-items-center onvo-gap-2 onvo-mt-2">
                  <Button
                    className="!onvo-rounded-full"
                    variant="secondary"
                    color="gray"
                    onClick={() => {
                      setEditing(false);
                    }}
                  >
                    Cancel
                  </Button>
                  <Button
                    className=" !onvo-rounded-full"
                    onClick={() => {
                      onEdit(newMessage);
                      setEditing(false);
                    }}
                  >
                    Save
                  </Button>
                </div>
              ) : (
                <Icon
                  onClick={() => {
                    setEditing(true)
                    setNewMessage(content as string);
                  }}
                  className="onvo-absolute onvo-cursor-pointer onvo-top-2 -onvo-left-8 onvo-hidden group-hover:onvo-block"
                  icon={PencilIcon}
                  variant="shadow"
                  size="xs"
                />
              )}
            </div>
          </div></div>
      );
    }


    const ImageDownloadEnabled = useMemo(() => {
      if (widget && widget.type === "table") return false;
      if (adminMode) return true;
      if (dashboard?.settings?.disable_download_images) return false;
      return true;
    }, [dashboard, adminMode, widget]);

    const ReportDownloadEnabled = useMemo(() => {
      if (adminMode) return true;
      if (dashboard?.settings?.disable_download_reports) return false;
      return true;
    }, [dashboard, adminMode]);

    const AddToDashboardEnabled = useMemo(() => {
      if (adminMode) return true;
      if (dashboard?.settings?.can_create_widgets) return true;
      return false;
    }, [dashboard, adminMode]);


    if (!widget && role === "assistant") {

      let answer = content || "";
      let options = [] as string[];

      if (answer.search("<option>") >= 0) {
        let opts = answer
          .match(/(<option>.*?<\/option>)/g)
          ?.map((a) => a.replace(/<option>/g, "").replace(/<\/option>/g, ""));
        let ans = answer.split("<option>")[0];
        answer = ans;
        options = opts || [];
      }

      return (
        <article className="onvo-question-assistant-code-wrapper onvo-max-w-none onvo-prose onvo-prose-sm dark:onvo-prose-invert onvo-w-full">
          {answer && answer.trim() !== "" && (
            <ErrorBoundary
              fallbackRender={({ error }) => <Text>{answer}</Text>}
            >
              <ReactMarkdown remarkPlugins={[remarkGfm]}>
                {answer}
              </ReactMarkdown>
            </ErrorBoundary>
          )}
          {options && options.length > 0 && (
            <div className="onvo-flex onvo-flex-col onvo-items-start onvo-justify-start onvo-gap-2 -onvo-mt-2">
              {options.map((a) => (
                <div
                  className={"onvo-px-3 onvo-py-2 onvo-flex onvo-flex-row onvo-gap-2 onvo-items-center onvo-rounded-2xl onvo-bg-black/5 dark:onvo-bg-white/10 onvo-transition-all onvo-animate-slideDownAndFade " + ((isLast && !questionLoading) ? "onvo-cursor-pointer hover:onvo-shadow-lg" : "")}
                  onClick={() => (isLast && !questionLoading) && onReply(a)}
                  key={a}
                >
                  <SparklesIcon className="onvo-size-4 onvo-text-blue-500" />
                  <Text className="!onvo-m-0 onvo-flex-grow">{a}</Text>
                  {(isLast && !questionLoading) && <ArrowRightIcon className="onvo-size-4" />}
                </div>
              ))}
            </div>
          )}
        </article>);
    }


    return (
      <div ref={elementRef} className="onvo-question-message-assistant onvo-animate-slideRightAndFade onvo-relative onvo-mb-3 onvo-flex onvo-flex-row onvo-items-start onvo-justify-start onvo-gap-3">

        <div className="onvo-w-full">
          {adminMode && widget?.code.trim() !== "" && (
            <Accordion
              type="single"
              className="onvo-leading-none onvo-mb-2"
              collapsible
            >
              <AccordionItem value="item-1" className="onvo-border-b-0">
                <div className="onvo-flex onvo-flex-row onvo-items-center onvo-gap-2 onvo-w-full">
                  <AccordionTrigger className="onvo-border-b-0 onvo-flex-grow onvo-w-full !onvo-py-1.5 !onvo-px-3 onvo-rounded-2xl onvo-bg-slate-100 dark:onvo-bg-slate-700">
                    <span>Show working</span>
                  </AccordionTrigger>
                  <Popover
                    open={explainingCode || explainedCode !== null}
                    onOpenChange={(open) => {
                      if (!open) setExplainedCode(null);
                    }}
                  >
                    <PopoverTrigger asChild>
                      <div className="onvo-py-2 onvo-px-3 onvo-cursor-pointer onvo-rounded-2xl onvo-bg-slate-100 dark:onvo-bg-slate-700" onClick={explainCode}>
                        <Text className="onvo-flex onvo-flex-row onvo-items-center hover:onvo-text-blue-500">
                          <SparklesIcon className="onvo-h-4 onvo-w-4 onvo-mr-2" />
                          Explain working
                        </Text>
                      </div>
                    </PopoverTrigger>
                    <PopoverContent className="onvo-w-96">
                      {explainingCode ? (
                        <div className="onvo-flex onvo-items-center onvo-space-x-2 onvo-p-4">
                          <div role="status">
                            <svg
                              aria-hidden="true"
                              className="onvo-inline onvo-w-6 onvo-h-6 onvo-text-gray-200 onvo-animate-spin dark:onvo-text-gray-600 onvo-fill-blue-600"
                              viewBox="0 0 100 101"
                              fill="none"
                              xmlns="http://www.w3.org/2000/svg"
                            >
                              <path
                                d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
                                fill="currentColor"
                              />
                              <path
                                d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
                                fill="currentFill"
                              />
                            </svg>
                          </div>
                          <Text>Explaining code...</Text>
                        </div>
                      ) : (
                        <div className="onvo-prose onvo-prose-sm dark:onvo-prose-invert onvo-max-h-[50vh] onvo-overflow-y-auto onvo-p-2">
                          <ReactMarkdown remarkPlugins={[remarkGfm]}>
                            {explainedCode || ""}
                          </ReactMarkdown>
                        </div>
                      )}
                    </PopoverContent>
                  </Popover>
                </div>
                <AccordionContent className="onvo-pt-2">
                  <ErrorBoundary
                    fallbackRender={({ error }) => <Text>{widget?.code}</Text>}
                  >
                    <article className="onvo-question-assistant-code-wrapper onvo-prose onvo-prose-slate onvo-prose-sm dark:onvo-prose-invert onvo-inline onvo-w-full">
                      <ReactMarkdown className="onvo-question-assistant-code !onvo-rounded-2xl -onvo-mt-5">
                        {"```python\n" + widget?.code + "\n```"}
                      </ReactMarkdown>
                    </article>
                  </ErrorBoundary>
                </AccordionContent>
              </AccordionItem>
            </Accordion>
          )}

          {(cache && widget) ? (
            <Card
              className={
                "onvo-group onvo-mt-2 onvo-question-assistant-chart onvo-foreground-color onvo-relative onvo-mb-2 onvo-px-0 onvo-py-0 onvo-flex onvo-flex-col"
              }
            >
              <div
                className={
                  "onvo-py-3 onvo-px-2 " +
                  (widget?.type === "metric" ? "onvo-h-32" : "onvo-h-96")
                }
              >

                <ChartBase
                  json={cache}
                  title={widget.title}
                />
              </div>
              <div
                className="onvo-chart-card-dropdown-wrapper onvo-py-2 onvo-px-2 onvo-z-20 onvo-border-solid onvo-border-t onvo-border-black/5 dark:onvo-border-white/10 onvo-rounded-b-2xl onvo-background-color onvo-flex onvo-w-full onvo-justify-between onvo-flex-row onvo-items-center"
                onClick={(e) => {
                  e.stopPropagation();
                  e.preventDefault();
                }}
                onMouseDown={(e) => {
                  e.stopPropagation();
                  e.preventDefault();
                }}
                onMouseUp={(e) => {
                  e.stopPropagation();
                  e.preventDefault();
                }}
              >
                <div className="onvo-flex onvo-gap-2 onvo-items-center">
                  {adminMode && (
                    <Button
                      variant="secondary"
                      onClick={() => onAdd(widget, true)}
                    >
                      Add to library
                    </Button>
                  )}
                </div>
                <div className="onvo-flex onvo-gap-2 onvo-items-center">
                  {AddToDashboardEnabled && (
                    <Button
                      variant="primary"
                      onClick={() => onAdd(widget, false)}
                    >
                      Add to dashboard
                    </Button>
                  )}
                  {(ImageDownloadEnabled || ReportDownloadEnabled) && (
                    <DropdownMenu modal={false}>
                      <DropdownMenuTrigger asChild>
                        <Icon variant="shadow" className="onvo-foreground-color onvo-border-black/10 dark:onvo-border-white/10" icon={ArrowDownTrayIcon} />
                      </DropdownMenuTrigger>
                      <DropdownMenuContent container={containerRef?.current} className="onvo-min-w-56 onvo-background-color onvo-border-black/10 dark:onvo-border-white/10">
                        {ReportDownloadEnabled && (
                          <>
                            <DropdownMenuLabel>Reports</DropdownMenuLabel>
                            <DropdownMenuGroup>
                              <DropdownMenuItem
                                onClick={() => onDownload("xlsx")}
                              >
                                <span className="onvo-flex onvo-items-center onvo-gap-x-2">
                                  <DocumentChartBarIcon className="onvo-size-4" />
                                  <span>Download as excel</span>
                                </span>
                              </DropdownMenuItem>
                              <DropdownMenuItem
                                onClick={() => onDownload("csv")}
                              >
                                <span className="onvo-flex onvo-items-center onvo-gap-x-2">
                                  <DropdownMenuIconWrapper>
                                    <DocumentChartBarIcon className="onvo-size-4 onvo-text-inherit" />
                                  </DropdownMenuIconWrapper>
                                  <span>Download as CSV</span>
                                </span>
                              </DropdownMenuItem>
                            </DropdownMenuGroup>
                          </>
                        )}
                        {ImageDownloadEnabled && ReportDownloadEnabled && (
                          <DropdownMenuSeparator className="onvo-border-black/10 dark:onvo-border-white/10" />
                        )}
                        {ImageDownloadEnabled && (
                          <>
                            <DropdownMenuLabel>Images</DropdownMenuLabel>
                            <DropdownMenuGroup>
                              <DropdownMenuItem
                                onClick={() => onDownload("svg")}
                              >
                                <span className="onvo-flex onvo-items-center onvo-gap-x-2">
                                  <PhotoIcon className="onvo-size-4" />
                                  <span>Download as SVG</span>
                                </span>
                              </DropdownMenuItem>
                              <DropdownMenuItem
                                onClick={() => onDownload("png")}
                              >
                                <span className="onvo-flex onvo-items-center onvo-gap-x-2">
                                  <DropdownMenuIconWrapper>
                                    <PhotoIcon className="onvo-size-4 onvo-text-inherit" />
                                  </DropdownMenuIconWrapper>
                                  <span>Download as PNG</span>
                                </span>
                              </DropdownMenuItem>
                              <DropdownMenuItem
                                onClick={() => onDownload("jpeg")}
                              >
                                <span className="onvo-flex onvo-items-center onvo-gap-x-2">
                                  <DropdownMenuIconWrapper>
                                    <PhotoIcon className="onvo-size-4 onvo-text-inherit" />
                                  </DropdownMenuIconWrapper>
                                  <span>Download as JPEG</span>
                                </span>
                              </DropdownMenuItem>
                            </DropdownMenuGroup>
                          </>
                        )}
                      </DropdownMenuContent>
                    </DropdownMenu>
                  )}
                </div>
              </div>
            </Card>
          ) : (
            <Card className="onvo-mt-2 onvo-relative">
              <div
                className={
                  (widget?.type === "metric" ? "onvo-h-32" : "onvo-h-72")
                }
              >
                <ChartPlaceholder
                  type={widget?.type || "bar"}
                  title={
                    questionLoading
                      ? "Generating " + (widget?.type || "bar") + " chart..."
                      : undefined
                  }
                  showProgress={questionLoading}
                />
              </div>
            </Card>
          )}

          <div className="onvo-flex onvo-items-center onvo-gap-1 onvo-mt-2 onvo-justify-start onvo-text-slate-900 dark:onvo-text-slate-100">
            {vote === "up" ? (
              <div className="onvo-size-8 onvo-rounded-full onvo-p-1.5 onvo-cursor-pointer hover:onvo-bg-black/10 dark:hover:onvo-bg-white/10">
                <HandThumbUpSolidIcon className="onvo-size-5" />
              </div>
            ) : (
              <VotePopover questionId={message.question} messageId={message.id} type="up" onSubmit={() => setVote("up")}>
                <div className="onvo-size-8 onvo-rounded-full onvo-p-1.5 onvo-cursor-pointer hover:onvo-bg-black/10 dark:hover:onvo-bg-white/10">
                  <HandThumbUpOutlineIcon className="onvo-size-5" />
                </div>
              </VotePopover>
            )}
            {vote === "down" ? (
              <div className="onvo-size-8 onvo-rounded-full onvo-p-1.5 onvo-cursor-pointer hover:onvo-bg-black/10 dark:hover:onvo-bg-white/10">
                <HandThumbDownSolidIcon className="onvo-size-5" />
              </div>
            ) : (
              <VotePopover questionId={message.question} messageId={message.id} type="down" onSubmit={() => setVote("down")}>
                <div className="onvo-size-8 onvo-rounded-full onvo-p-1.5 onvo-cursor-pointer hover:onvo-bg-black/10 dark:hover:onvo-bg-white/10">
                  <HandThumbDownOutlineIcon className="onvo-size-5" />
                </div>
              </VotePopover>
            )}
          </div>
        </div>
      </div>
    );
  };