"use client"

import * as React from "react"
import Image from "next/image"
import { format } from "date-fns"
import { Send, Loader2, X, Download, Eye, ImagePlus, Calendar, Bell } from "lucide-react"
import { DatePicker } from "@/components/ui/date-picker"
import { DateTimePicker } from "@/components/ui/date-time-picker"
import { cn } from "@/lib/utils"
import { Fancybox } from "@fancyapps/ui/dist/fancybox/"
import "@fancyapps/ui/dist/fancybox/fancybox.css"

/** Sanitize note HTML for safe display: allow only img (with safe src), br, and text. */
export function sanitizeNoteHtml(html: string | null): string {
  if (!html || !html.trim()) return ""
  let s = html
  // Remove script, iframe, object, embed
  s = s.replace(/<script\b[^<]*(?:(?!<\/script>)<)[^<]*<\/script>/gi, "")
  s = s.replace(/<iframe[^>]*>[\s\S]*?<\/iframe>/gi, "")
  s = s.replace(/<object\b[^<]*(?:(?!<\/object>)<)[^<]*<\/object>/gi, "")
  s = s.replace(/<embed\b[^>]*>/gi, "")
  // Sanitize img: only allow src (http/https or relative), no javascript:
  s = s.replace(/<img([^>]*)>/gi, (_, attrs) => {
    const srcMatch = attrs.match(/src=["']([^"']+)["']/i)
    const src = srcMatch ? srcMatch[1].trim() : ""
    if (!src || /^\s*javascript:/i.test(src)) return ""
    return `<img src="${src.replace(/"/g, "&quot;")}" loading="lazy" class="w-[150px] h-[150px] object-cover rounded-lg mt-1 border-2 border-gray-200 shadow-sm" alt="" />`
  })
  return s
}

/** Get plain text from note HTML for editing (strips images and tags). */
export function getEditableTextFromNote(html: string | null): string {
  if (!html || !html.trim()) return ""
  let s = html
    .replace(/<img[^>]*>/gi, "")
    .replace(/<br\s*\/?>/gi, "\n")
    .replace(/<\/div>/gi, "\n")
    .replace(/<div[^>]*>/gi, "\n")
    .replace(/<[^>]+>/g, " ")
    .replace(/&nbsp;/gi, " ")
    .replace(/\n{3,}/g, "\n\n")
    .trim()
  return s
}

/** Get image URLs from note HTML for display (e.g. in edit mode). */
export function getNoteImageUrls(html: string | null, apiBaseUrl: string): string[] {
  if (!html || !html.trim()) return []
  const base = apiBaseUrl.replace(/\/$/, "")
  const matches = [...html.matchAll(/<img[^>]+src=["']([^"']+)["']/gi)]
  return matches.map((m) => {
    const src = m[1].trim()
    if (src.startsWith("http")) return src
    return src.startsWith("/") ? `${base}${src}` : `${base}/${src}`
  })
}

/** Merge edited plain text with original note's images for save. */
export function mergeEditedNoteText(editedPlainText: string, originalHtml: string): string {
  const escape = (t: string) =>
    t.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")
  const textHtml = escape(editedPlainText.trim()).replace(/\n/g, "<br/>")
  const imgTags = (originalHtml.match(/<img[^>]*>/gi) ?? []).join("")
  if (!imgTags) return textHtml
  return textHtml ? `${textHtml}<br/>${imgTags}` : imgTags
}

const STORED_IMG_TAG =
  '<img src="__SRC__" loading="lazy" class="w-[150px] h-[150px] object-cover rounded-lg border-2 border-gray-200 shadow-sm" alt="" />'

/** Merge edited text with only the remaining image URLs (for save when user removed some in edit). */
export function mergeEditedNoteTextWithImages(
  editedPlainText: string,
  remainingImageUrls: string[],
  apiBaseUrl: string
): string {
  const escape = (t: string) =>
    t.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")
  const textHtml = escape(editedPlainText.trim()).replace(/\n/g, "<br/>")
  const base = apiBaseUrl.replace(/\/$/, "")
  const imgTags = remainingImageUrls
    .map((url) => {
      const rel = url.startsWith(base) ? url.slice(base.length).replace(/^(?!\/)/, "/") : url
      return STORED_IMG_TAG.replace("__SRC__", rel.replace(/"/g, "&quot;"))
    })
    .join("")
  if (!imgTags) return textHtml
  return textHtml ? `${textHtml}<br/>${imgTags}` : imgTags
}

const IMG_CLASS =
  "w-full h-full min-h-[120px] max-h-[200px] object-cover rounded-lg border-2 border-gray-200 shadow-sm"

/** Render note text: plain text or sanitized HTML; images in FB-style grid. */
export function NoteContent({
  text,
  apiBaseUrl,
  className,
  imageUrl,
  dueDate,
  reminderAt,
}: {
  text: string | null
  apiBaseUrl: string
  className?: string
  imageUrl?: string | null
  dueDate?: string | null
  reminderAt?: string | null
}) {
  const galleryId = React.useId().replace(/:/g, "")
  const galleryRef = React.useRef<HTMLDivElement>(null)

  const parsedGallery = React.useMemo(() => {
    const sanitized = text ? sanitizeNoteHtml(text) : ""
    const withBaseUrl = sanitized.replace(
      /src="(\/[^"]+)"/g,
      (_, path: string) => `src="${apiBaseUrl}${path}"`,
    )
    const textImages = [
      ...withBaseUrl.matchAll(/<img[^>]+src=["']([^"']+)["']/gi),
    ].map((m) => m[1])

    const imageUrls = [...textImages]
    if (imageUrl) {
      const resolved = imageUrl.startsWith("http") ? imageUrl : `${apiBaseUrl}${imageUrl.startsWith("/") ? "" : "/"}${imageUrl}`
      if (!imageUrls.includes(resolved)) imageUrls.push(resolved)
    }

    if (imageUrls.length === 0 && !text) return null

    const textHtml = withBaseUrl.replace(/<img[^>]*>/gi, "").trim()
    return { imageUrls, textHtml }
  }, [text, apiBaseUrl, imageUrl])

  React.useEffect(() => {
    if (!parsedGallery || parsedGallery.imageUrls.length === 0) return
    const el = galleryRef.current
    if (!el) return
    Fancybox.bind(el, "[data-fancybox]", {
      Hash: false,
    })
    return () => Fancybox.unbind(el, "[data-fancybox]")
  }, [parsedGallery])

  if (!parsedGallery) {
    return (
      <p
        className={cn(
          "text-[14px] text-gray-700 leading-relaxed whitespace-pre-wrap break-words",
          className,
        )}
      >
        {text}
      </p>
    )
  }

  const { imageUrls, textHtml } = parsedGallery

  const handleDownloadImage = (src: string, index: number) => {
    fetch(src, { mode: "cors" })
      .then((r) => r.blob())
      .then((blob) => {
        const url = URL.createObjectURL(blob)
        const a = document.createElement("a")
        a.href = url
        a.download = `note-image-${index + 1}.png`
        a.click()
        URL.revokeObjectURL(url)
      })
      .catch(() => {
        window.open(src, "_blank", "noopener,noreferrer")
      })
  }

  return (
    <div className={cn("text-[14px] text-gray-700 leading-relaxed break-words space-y-3", className)}>
      {(dueDate || reminderAt) && (
        <div className="flex flex-wrap gap-3 pb-1 border-b border-gray-100/50">
          {dueDate && (
            <div className="flex items-center gap-1.5 px-2 py-0.5 bg-orange-50 text-orange-600 rounded-md text-[11px] font-bold uppercase tracking-wider border border-orange-100/50">
              <Calendar className="size-3" />
              Due: {format(new Date(dueDate), "MMM d, yyyy")}
            </div>
          )}
          {reminderAt && (
            <div className="flex items-center gap-1.5 px-2 py-0.5 bg-indigo-50 text-indigo-600 rounded-md text-[11px] font-bold uppercase tracking-wider border border-indigo-100/50">
              <Bell className="size-3" />
              Remind: {format(new Date(reminderAt), "MMM d, h:mm a")}
            </div>
          )}
        </div>
      )}
      {textHtml ? (
        <div
          className="[&_br]:block [&_br]:h-2"
          dangerouslySetInnerHTML={{ __html: textHtml }}
        />
      ) : null}
      {imageUrls.length > 0 ? (
        <div
          ref={galleryRef}
          className={cn(
            "grid gap-2 w-full",
            imageUrls.length === 1 && "grid-cols-1 max-w-[200px]",
            imageUrls.length === 2 && "grid-cols-2 max-w-[320px]",
            imageUrls.length >= 3 && "grid-cols-3 max-w-[420px]"
          )}
        >
          {imageUrls.map((src, i) => (
            <div key={`${src}-${i}`} className="relative aspect-square min-h-[100px] overflow-hidden rounded-lg bg-gray-100 group">
              <Image
                src={src}
                alt=""
                fill
                loading="lazy"
                sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
                className={IMG_CLASS}
              />
              <div className="absolute inset-x-0 bottom-0 flex items-center justify-center gap-2 py-1.5 bg-black/50 text-white text-[11px] font-medium opacity-0 group-hover:opacity-100 transition-opacity">
                <a
                  href={src}
                  data-fancybox={galleryId}
                  data-caption={`Image ${i + 1}`}
                  className="flex items-center gap-1 rounded px-2 py-1 hover:bg-white/20 text-inherit no-underline"
                  onClick={(e) => e.stopPropagation()}
                >
                  <Eye className="h-3.5 w-3.5" />
                  View
                </a>
                <button
                  type="button"
                  onClick={() => handleDownloadImage(src, i)}
                  className="flex items-center gap-1 rounded px-2 py-1 hover:bg-white/20"
                >
                  <Download className="h-3.5 w-3.5" />
                  Download
                </button>
              </div>
            </div>
          ))}
        </div>
      ) : null}
    </div>
  )
}

export interface DealNoteComposerProps {
  dealId: string
  apiBaseUrl: string
  placeholder?: string
  disabled?: boolean
  onSend: (html: string, dueDate?: string, reminderAt?: string) => void | Promise<void>
  uploadImage: (dealId: string, file: File) => Promise<{ url: string }>
  className?: string
}

export function DealNoteComposer({
  dealId,
  apiBaseUrl,
  placeholder = "Add an internal note... (paste image to attach)",
  disabled,
  onSend,
  uploadImage,
  className,
}: DealNoteComposerProps) {
  const ref = React.useRef<HTMLDivElement>(null)
  const [uploading, setUploading] = React.useState(false)
  const [sending, setSending] = React.useState(false)
  const [attachedImages, setAttachedImages] = React.useState<string[]>([])
  const [hasContent, setHasContent] = React.useState(false)

  const fileInputRef = React.useRef<HTMLInputElement>(null)


  const checkContent = () => {
    if (attachedImages.length > 0) {
      setHasContent(true)
      return
    }
    if (ref.current) {
      const text = ref.current.textContent?.trim()
      const hasImg = ref.current.querySelector('img')
      setHasContent(!!(text || hasImg))
    } else {
      setHasContent(false)
    }
  }

  React.useEffect(() => {
    checkContent()
  }, [attachedImages])

  const resolveDisplayUrl = (url: string) =>
    url.startsWith("http")
      ? url
      : `${apiBaseUrl.replace(/\/$/, "")}${url.startsWith("/") ? url : `/${url}`}`

  const getHtml = () => {
    if (!ref.current) return ""
    return ref.current.innerHTML.trim()
  }

  const setHtml = (html: string) => {
    if (ref.current) {
      ref.current.innerHTML = html
    }
  }

  const handleFileSelect = async (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0]
    if (!file) return
    if (!file.type.startsWith("image/")) {
      alert("Please select an image file")
      return
    }
    setUploading(true)
    try {
      const { url } = await uploadImage(dealId, file)
      setAttachedImages((prev) => [...prev, resolveDisplayUrl(url)])
    } catch (err) {
      console.error("Failed to upload selected image:", err)
    } finally {
      setUploading(false)
      if (fileInputRef.current) fileInputRef.current.value = ""
    }
  }

  const handlePaste = async (e: React.ClipboardEvent) => {
    const items = e.clipboardData?.items
    if (!items) return
    for (const item of items) {
      if (item.type.indexOf("image") !== -1) {
        e.preventDefault()
        const file = item.getAsFile()
        if (!file) return
        setUploading(true)
        try {
          const { url } = await uploadImage(dealId, file)
          setAttachedImages((prev) => [...prev, resolveDisplayUrl(url)])
        } catch (err) {
          console.error("Failed to upload pasted image:", err)
        } finally {
          setUploading(false)
        }
        return
      }
    }
  }

  const removeAttachedImage = (index: number) => {
    setAttachedImages((prev) => prev.filter((_, i) => i !== index))
  }

  const handleSend = async () => {
    const html = getHtml()
    const textOnly = (ref.current?.textContent?.trim() ?? "") || ""
    const hasImages = attachedImages.length > 0 || (ref.current?.querySelector('img') !== null)

    if (!textOnly && !hasImages) return

    const base = apiBaseUrl.replace(/\/$/, "")
    const imgTags = attachedImages
      .map((url) => {
        const rel = url.startsWith(base) ? url.slice(base.length).replace(/^(?!\/)/, "/") : url
        return `<img src="${rel.replace(/"/g, "&quot;")}" loading="lazy" class="w-[150px] h-[150px] object-cover rounded-lg border-2 border-gray-200 shadow-sm" alt="" />`
      })
      .join("")
    const combined = (html || "").trim() ? `${html.trim()}${imgTags ? `<br/>${imgTags}` : ""}` : imgTags
    const forStorage = combined.replace(
      new RegExp(base.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "g"),
      ""
    )

    setSending(true)
    try {
      await onSend(forStorage)
      setHtml("")
      setAttachedImages([])
    } finally {
      setSending(false)
    }
  }

  const handleKeyDown = (e: React.KeyboardEvent) => {
    if (e.key === "Enter" && !e.shiftKey) {
      e.preventDefault()
      if (!disabled && !sending && hasContent) {
        handleSend()
      }
    }
  }

  return (
    <div className={cn("relative space-y-2", className)}>
      {attachedImages.length > 0 ? (
        <div className="flex gap-2 overflow-x-auto pb-2 px-1">
          {attachedImages.map((url, i) => (
            <div
              key={`${url}-${i}`}
              className="relative shrink-0 w-[72px] h-[72px] rounded-lg overflow-hidden border-2 border-gray-200 shadow-sm bg-gray-100 group"
            >
              <Image
                src={url}
                alt=""
                fill
                loading="lazy"
                sizes="(max-width: 768px) 100px, 100px"
                className="w-full h-full object-cover"
              />
              <button
                type="button"
                onClick={() => removeAttachedImage(i)}
                className="absolute top-0.5 right-0.5 h-5 w-5 rounded-full bg-black/60 text-white flex items-center justify-center opacity-0 group-hover:opacity-100 focus:opacity-100 transition-opacity"
                aria-label="Remove image"
              >
                <X className="h-3 w-3" />
              </button>
            </div>
          ))}
        </div>
      ) : null}
      <div className="overflow-hidden rounded-xl border border-gray-200 bg-gray-50/80 shadow-sm ring-1 ring-black/[0.03]">
        <div
          ref={ref}
          contentEditable={!disabled}
          spellCheck={false}
          onPaste={handlePaste}
          onInput={checkContent}
          onKeyDown={handleKeyDown}
          data-placeholder={placeholder}
          className={cn(
            "min-h-[100px] max-h-[min(40vh,280px)] overflow-y-auto bg-white px-4 py-3 text-[13px] text-gray-900 outline-none",
            "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-inset focus-visible:ring-[#6C63FF]/25",
            "empty:before:pointer-events-none empty:before:text-gray-400 empty:before:content-[attr(data-placeholder)]",
          )}
          suppressContentEditableWarning
        />

        <input
          type="file"
          ref={fileInputRef}
          className="hidden"
          accept="image/*"
          onChange={handleFileSelect}
        />

        <div className="flex items-center justify-between gap-3 border-t border-gray-200/90 bg-gray-50 px-3 py-2">
          <button
            type="button"
            disabled={disabled || uploading || sending}
            onClick={() => fileInputRef.current?.click()}
            className="flex h-9 shrink-0 items-center gap-1.5 rounded-lg px-2.5 text-[11px] font-medium text-gray-600 transition-colors hover:bg-white hover:text-[#6C63FF] disabled:opacity-30"
            title="Upload image"
          >
            {uploading ? <Loader2 size={14} className="animate-spin" /> : <ImagePlus size={14} />}
            <span>Image</span>
          </button>

          <button
            type="button"
            disabled={disabled || !hasContent || sending}
            onClick={handleSend}
            className="flex h-9 shrink-0 items-center justify-center gap-2 rounded-lg bg-[#6C63FF] px-4 text-white shadow-sm transition-all hover:bg-[#5a52e0] disabled:opacity-30"
          >
            {sending ? <Loader2 size={14} className="animate-spin" /> : <Send size={14} />}
            <span className="text-[12px] font-semibold">Send Note</span>
          </button>
        </div>
      </div>
    </div>
  )
}
