import { useCrypto } from "@tensamin/crypto/context";
import * as React from "react";
import { useChat } from "../context";
import type { RawMessage } from "../values";
import { log } from "@tensamin/shared/log";
import Text from "@tensamin/markdown/text";
import { AlertTriangle, Clock } from "lucide-react";

import {
  Tooltip,
  TooltipContent,
  TooltipTrigger,
} from "@tensamin/ui/cmp/tooltip";
import { useIsMobile } from "@tensamin/ui/utils";
import {
  ContextMenu,
  ContextMenuContent,
  ContextMenuItem,
  ContextMenuTrigger,
} from "@tensamin/ui/cmp/context-menu";

function generateFixedLoadingSize(size: number, height: number) {
  return size * 3 - (height / 20) * 11;
}

/**
 * Executes Message.
 * @param props Parameter props.
 * @returns unknown.
 */
function MessageComponent(props: {
  message: RawMessage & {
    failed?: boolean;
  };
  notEncrypted?: boolean;
  measureRef?: React.Ref<HTMLDivElement>;
}) {
  const { sharedSecret } = useChat();
  const { decrypt } = useCrypto();

  const isMobile = useIsMobile();

  const [decodedContent, setDecodedContent] = React.useState("");
  const [isReady, setIsReady] = React.useState(false);

  React.useEffect(() => {
    if (props.notEncrypted) {
      setDecodedContent(props.message.content);
      setIsReady(true);
      return;
    }

    const content = props.message.content;
    const secret = sharedSecret;
    let active = true;

    if (!secret) {
      setIsReady(false);
      return;
    }

    decrypt(secret, content)
      .then((value) => {
        if (!active) {
          return;
        }

        setDecodedContent(value);
        setIsReady(true);
      })
      .catch((e) => {
        if (!active) {
          return;
        }

        log(0, "Chat", "red", "Failed to decrypt message", e, {
          content,
          secret,
        });

        setDecodedContent("Failed to decrypt");
        setIsReady(true);
      });

    return () => {
      active = false;
    };
  }, [decrypt, props.message.content, props.notEncrypted, sharedSecret]);

  return (
    <div
      ref={props.measureRef}
      className={`w-full flex justify-start transition-opacity duration-150 ${(props.message.failed || props.message.message_state === "awaiting") && "opacity-50"}`}
    >
      <ContextMenu>
        <ContextMenuTrigger
          render={
            <div
              className={`selection-foreground flex gap-1 items-center justify-center max-w-[80%] rounded-lg px-2 py-px whitespace-pre-wrap break-all ${
                props.message.sent_by_self
                  ? props.message.failed
                    ? "bg-destructive/75 text-destructive-foreground"
                    : "bg-primary text-primary-foreground"
                  : "bg-muted"
              } ${!isReady && "animate-pulse"} ${isMobile && "select-none"}`}
            >
              {props.message.failed &&
                props.message.message_state === "awaiting" && (
                  <Tooltip>
                    <TooltipContent>
                      <p>Failed to send message</p>
                    </TooltipContent>
                    <TooltipTrigger render={<AlertTriangle size={17} />} />
                  </Tooltip>
                )}
              {!props.message.failed &&
                props.message.message_state === "awaiting" && (
                  <Clock size={17} />
                )}
              {isReady ? (
                <Text value={decodedContent} />
              ) : (
                <div
                  className="h-8"
                  style={{
                    width: generateFixedLoadingSize(
                      props.message.content.length,
                      props.message.height,
                    ),
                    height: props.message.height,
                  }}
                />
              )}
            </div>
          }
        />
        <ContextMenuContent>
          <ContextMenuItem>
            <Text value={decodedContent} />
          </ContextMenuItem>
        </ContextMenuContent>
      </ContextMenu>
    </div>
  );
}

export default React.memo(MessageComponent, (prev, next) => {
  return (
    prev.notEncrypted === next.notEncrypted &&
    prev.measureRef === next.measureRef &&
    prev.message.timestamp === next.message.timestamp &&
    prev.message.content === next.message.content &&
    prev.message.height === next.message.height &&
    prev.message.sent_by_self === next.message.sent_by_self &&
    prev.message.message_state === next.message.message_state &&
    prev.message.failed === next.message.failed
  );
});
