import type { Element } from "hast";
import { ChevronDown, ChevronUp } from "lucide-react";
import { memo, useMemo } from "react";
import ReactMarkdown from "react-markdown";
import rehypeKatex from "rehype-katex";
import rehypeRaw from "rehype-raw";
import rehypeSanitize from "rehype-sanitize";
import remarkBreaks from "remark-breaks";
import remarkGfm from "remark-gfm";
import remarkMath from "remark-math";
import { cn } from "@/lib/utils";
import { useTranslate } from "@/utils/i18n";
import { rehypeHeadingId } from "@/utils/rehype-plugins/rehype-heading-id";
import { remarkDisableSetext } from "@/utils/remark-plugins/remark-disable-setext";
import { extractMentionUsernames, remarkMention } from "@/utils/remark-plugins/remark-mention";
import { remarkPreserveType } from "@/utils/remark-plugins/remark-preserve-type";
import { remarkTag } from "@/utils/remark-plugins/remark-tag";
import { CodeBlock } from "./CodeBlock";
import { isMentionNode, isTagNode, isTaskListItemNode } from "./ConditionalComponent";
import { COMPACT_MODE_CONFIG, SANITIZE_SCHEMA } from "./constants";
import { useCompactLabel, useCompactMode } from "./hooks";
import { Mention } from "./Mention";
import { useResolvedMentionUsernames } from "./MentionResolutionContext";
import { Blockquote, Heading, HorizontalRule, Image, InlineCode, Link, List, ListItem, Paragraph } from "./markdown";
import { Table, TableBody, TableCell, TableHead, TableHeaderCell, TableRow } from "./Table";
import { Tag } from "./Tag";
import { TaskListItem } from "./TaskListItem";
import { TrustedIframe } from "./TrustedIframe";
import type { MemoContentProps } from "./types";

function getMentionUsername(node: Element, children?: React.ReactNode): string {
  const dataMention = node.properties?.["data-mention"];
  if (typeof dataMention === "string" && dataMention !== "") {
    return dataMention;
  }

  const camelDataMention = (node.properties as Record<string, unknown> | undefined)?.dataMention;
  if (typeof camelDataMention === "string" && camelDataMention !== "") {
    return camelDataMention;
  }

  const text = Array.isArray(children) ? children.join("") : children;
  if (typeof text === "string" && text.startsWith("@")) {
    return text.slice(1).toLowerCase();
  }

  return "";
}

const MemoContent = (props: MemoContentProps) => {
  const { className, contentClassName, content, onClick, onDoubleClick } = props;
  const t = useTranslate();
  const {
    containerRef: memoContentContainerRef,
    mode: showCompactMode,
    toggle: toggleCompactMode,
  } = useCompactMode(Boolean(props.compact));
  const mentionUsernames = useMemo(() => extractMentionUsernames(content), [content]);
  const resolvedMentionUsernames = useResolvedMentionUsernames(mentionUsernames);

  const compactLabel = useCompactLabel(showCompactMode, t as (key: string) => string);

  return (
    <div className={`w-full flex flex-col justify-start items-start text-foreground ${className || ""}`}>
      <div
        ref={memoContentContainerRef}
        data-memo-content
        className={cn(
          "relative w-full max-w-full wrap-break-word text-base leading-6",
          "[&>*:last-child]:mb-0",
          "[&_.katex-display]:max-w-full",
          "[&_.katex-display]:overflow-x-auto",
          "[&_.katex-display]:overflow-y-hidden",
          showCompactMode === "ALL" && "overflow-hidden",
          contentClassName,
        )}
        style={showCompactMode === "ALL" ? { maxHeight: `${COMPACT_MODE_CONFIG.maxHeightVh}vh` } : undefined}
        onMouseUp={onClick}
        onDoubleClick={onDoubleClick}
      >
        <ReactMarkdown
          remarkPlugins={[remarkDisableSetext, remarkMath, remarkGfm, remarkBreaks, remarkMention, remarkTag, remarkPreserveType]}
          rehypePlugins={[
            rehypeRaw,
            [rehypeSanitize, SANITIZE_SCHEMA],
            rehypeHeadingId,
            [rehypeKatex, { throwOnError: false, strict: false }],
          ]}
          components={{
            // Child components consume from MemoViewContext directly
            input: ((inputProps: React.ComponentProps<"input"> & { node?: Element }) => {
              const { node, ...rest } = inputProps;
              if (node && isTaskListItemNode(node)) {
                return <TaskListItem {...inputProps} />;
              }
              return <input {...rest} />;
            }) as React.ComponentType<React.ComponentProps<"input">>,
            span: ((spanProps: React.ComponentProps<"span"> & { node?: Element }) => {
              const { node, ...rest } = spanProps;
              if (node && isMentionNode(node)) {
                const username = getMentionUsername(node, spanProps.children);
                return <Mention {...spanProps} data-mention={username} resolved={resolvedMentionUsernames.has(username)} />;
              }
              if (node && isTagNode(node)) {
                return <Tag {...spanProps} />;
              }
              return <span {...rest} />;
            }) as React.ComponentType<React.ComponentProps<"span">>,
            // Headings
            h1: ({ children, ...props }) => (
              <Heading level={1} {...props}>
                {children}
              </Heading>
            ),
            h2: ({ children, ...props }) => (
              <Heading level={2} {...props}>
                {children}
              </Heading>
            ),
            h3: ({ children, ...props }) => (
              <Heading level={3} {...props}>
                {children}
              </Heading>
            ),
            h4: ({ children, ...props }) => (
              <Heading level={4} {...props}>
                {children}
              </Heading>
            ),
            h5: ({ children, ...props }) => (
              <Heading level={5} {...props}>
                {children}
              </Heading>
            ),
            h6: ({ children, ...props }) => (
              <Heading level={6} {...props}>
                {children}
              </Heading>
            ),
            // Block elements
            p: ({ children, ...props }) => <Paragraph {...props}>{children}</Paragraph>,
            blockquote: ({ children, ...props }) => <Blockquote {...props}>{children}</Blockquote>,
            hr: (props) => <HorizontalRule {...props} />,
            // Lists
            ul: ({ children, ...props }) => <List {...props}>{children}</List>,
            ol: ({ children, ...props }) => (
              <List ordered {...props}>
                {children}
              </List>
            ),
            li: ({ children, ...props }) => <ListItem {...props}>{children}</ListItem>,
            // Inline elements
            a: ({ children, ...props }) => <Link {...props}>{children}</Link>,
            code: ({ children, ...props }) => <InlineCode {...props}>{children}</InlineCode>,
            iframe: TrustedIframe as React.ComponentType<React.ComponentProps<"iframe">>,
            img: ({ ...props }) => <Image {...props} />,
            // Code blocks
            pre: CodeBlock,
            // Tables
            table: ({ children, ...props }) => <Table {...props}>{children}</Table>,
            thead: ({ children, ...props }) => <TableHead {...props}>{children}</TableHead>,
            tbody: ({ children, ...props }) => <TableBody {...props}>{children}</TableBody>,
            tr: ({ children, ...props }) => <TableRow {...props}>{children}</TableRow>,
            th: ({ children, ...props }) => <TableHeaderCell {...props}>{children}</TableHeaderCell>,
            td: ({ children, ...props }) => <TableCell {...props}>{children}</TableCell>,
          }}
        >
          {content}
        </ReactMarkdown>
        {showCompactMode === "ALL" && (
          <div
            className={cn(
              "absolute inset-x-0 bottom-0 pointer-events-none",
              COMPACT_MODE_CONFIG.gradientHeight,
              "bg-linear-to-t from-background from-0% via-background/60 via-40% to-transparent to-100%",
            )}
          />
        )}
      </div>
      {showCompactMode !== undefined && (
        <div className="relative w-full mt-2">
          <button
            type="button"
            className="group inline-flex items-center gap-1 px-2 py-1 text-xs text-muted-foreground hover:text-foreground transition-colors"
            onClick={toggleCompactMode}
          >
            <span>{compactLabel}</span>
            {showCompactMode === "ALL" ? <ChevronDown className="w-3 h-3" /> : <ChevronUp className="w-3 h-3" />}
          </button>
        </div>
      )}
    </div>
  );
};

export default memo(MemoContent);
