import { useCallback, useRef, useState, type ClipboardEvent } from "react"
import { PictureOutlined } from "@ant-design/icons"
import Editor, {
  BtnBold,
  BtnBulletList,
  BtnClearFormatting,
  BtnItalic,
  BtnLink,
  BtnNumberedList,
  BtnRedo,
  BtnStrikeThrough,
  BtnUnderline,
  BtnUndo,
  Separator,
  Toolbar,
  type ContentEditableEvent,
} from "react-simple-wysiwyg"
import { toast } from "../utils/toast"
import { normalizeMediaUrl } from "../utils/richText"

export interface RichTextImageUploadResult {
  url: string
  name?: string | null
}

/**
 * Max image display width in the editor/reader. We inject this as a style
 * attribute so images render at a reasonable size in the editor without
 * consuming full-resolution pixels during composition.
 */
const MAX_IMG_DISPLAY_WIDTH = 960

function buildImageHtml(imageUrl: string, alt: string): string {
  const escapedUrl = escapeAttr(imageUrl)
  const escapedAlt = escapeAttr(alt)
  // Use a wrapper + style to constrain the image visually while
  // keeping the src pointing to the full-resolution URL for preview.
  return (
    `<p>` +
    `<img src="${escapedUrl}" alt="${escapedAlt}" loading="lazy" decoding="async" ` +
    `style="max-width:min(100%,${MAX_IMG_DISPLAY_WIDTH}px);height:auto;display:block;border-radius:6px;margin:8px 0;" />` +
    `</p>`
  )
}

export default function RichTextEditor({
  value,
  onChange,
  placeholder,
  uploadImage,
}: {
  value?: string
  onChange?: (value: string) => void
  placeholder?: string
  uploadImage?: (file: File) => Promise<RichTextImageUploadResult>
}) {
  const inputRef = useRef<HTMLInputElement | null>(null)
  const [uploading, setUploading] = useState(false)

  const uploadSingleImage = useCallback(async (file: File) => {
    if (!uploadImage) return ""
    const result = await uploadImage(file)
    const imageUrl = normalizeMediaUrl(result.url)
    return buildImageHtml(imageUrl, result.name || file.name || "图片")
  }, [uploadImage])

  const handleImageSelect = useCallback(async (file: File | undefined) => {
    if (!file || !uploadImage) return
    setUploading(true)
    try {
      onChange?.(`${value || ""}${await uploadSingleImage(file)}`)
      toast.success("图片已上传")
    } catch (error) {
      const detail = (error as { response?: { data?: { detail?: unknown } } })?.response?.data?.detail
      toast.error(detail || "图片上传失败")
    } finally {
      setUploading(false)
      if (inputRef.current) inputRef.current.value = ""
    }
  }, [onChange, uploadImage, uploadSingleImage, value])

  const handlePaste = useCallback(async (event: ClipboardEvent<HTMLElement>) => {
    if (!uploadImage) return
    const imageFiles = Array.from(event.clipboardData.items)
      .filter((item) => item.kind === "file" && item.type.startsWith("image/"))
      .map((item) => item.getAsFile())
      .filter((file): file is File => Boolean(file))

    if (imageFiles.length === 0) return

    event.preventDefault()
    setUploading(true)
    try {
      let nextValue = value || ""
      for (const file of imageFiles) {
        nextValue += await uploadSingleImage(file)
      }
      onChange?.(nextValue)
      toast.success(imageFiles.length > 1 ? `${imageFiles.length} 张图片已上传` : "图片已上传")
    } catch (error) {
      const detail = (error as { response?: { data?: { detail?: unknown } } })?.response?.data?.detail
      toast.error(detail || "图片上传失败")
    } finally {
      setUploading(false)
    }
  }, [onChange, uploadImage, uploadSingleImage, value])

  return (
    <>
      <Editor
        containerProps={{ className: "qycw-rich-text-editor" }}
        value={value || ""}
        placeholder={placeholder}
        onChange={(event: ContentEditableEvent) => onChange?.(event.target.value)}
        onPaste={handlePaste}
      >
        <Toolbar>
          <BtnUndo />
          <BtnRedo />
          <Separator />
          <BtnBold />
          <BtnItalic />
          <BtnUnderline />
          <BtnStrikeThrough />
          <Separator />
          <BtnNumberedList />
          <BtnBulletList />
          <Separator />
          <BtnLink />
          {uploadImage && (
            <button
              type="button"
              className="rsw-btn"
              title="上传图片"
              disabled={uploading}
              onMouseDown={(event) => event.preventDefault()}
              onClick={() => inputRef.current?.click()}
            >
              <PictureOutlined />
            </button>
          )}
          <BtnClearFormatting />
        </Toolbar>
      </Editor>
      {uploadImage && (
        <input
          ref={inputRef}
          type="file"
          accept="image/jpeg,image/png,image/gif,image/webp"
          style={{ display: "none" }}
          onChange={(event) => void handleImageSelect(event.target.files?.[0])}
        />
      )}
    </>
  )
}

function escapeAttr(value: string) {
  return value
    .replace(/&/g, "&amp;")
    .replace(/"/g, "&quot;")
    .replace(/</g, "&lt;")
    .replace(/>/g, "&gt;")
}
