"use client"

import { memo, useCallback, useRef, type ReactNode, type TouchEvent } from "react"
import { Archive, Star, Tag, Trash2 } from "lucide-react"
import { cn } from "@/lib/utils"

const SNAP_MS = 200
const SNAP_EASE = "cubic-bezier(0.25, 0.46, 0.45, 0.94)"
const LEFT_PANEL_PX = 240
const RIGHT_PANEL_PX = 100
const OPEN_THRESHOLD_RATIO = 0.15
const OPEN_VELOCITY = 0.28

type Props = {
  enabled: boolean
  emailId: string
  isOpen: boolean
  onOpenChange: (open: boolean) => void
  onArchive: () => void
  onDelete: () => void
  onStar: () => void
  onLabel: () => void
  className?: string
  children: ReactNode
}

function MailListSwipeRowInner({
  enabled,
  emailId,
  isOpen,
  onOpenChange,
  onArchive,
  onDelete,
  onStar,
  onLabel,
  className,
  children,
}: Props) {
  const rowRef = useRef<HTMLDivElement>(null)
  const fgRef = useRef<HTMLDivElement>(null)
  const leftPanelRef = useRef<HTMLDivElement>(null)
  const rightPanelRef = useRef<HTMLDivElement>(null)

  const offsetRef = useRef(0)
  const directionRef = useRef<"none" | "left" | "right">("none")
  const touchRef = useRef<{
    startX: number
    startY: number
    startOffset: number
    active: boolean
    axis: "none" | "x" | "y"
    startTime: number
    prevX: number
    prevT: number
  } | null>(null)
  const suppressClickUntilRef = useRef(0)


  const applyOffset = useCallback((px: number) => {
    offsetRef.current = px
    const fg = fgRef.current
    if (!fg) return
    fg.style.transform = `translate3d(${px}px,0,0)`

    const lp = leftPanelRef.current
    const rp = rightPanelRef.current
    if (lp) lp.style.visibility = px > 0 ? "visible" : "hidden"
    if (rp) rp.style.visibility = px < 0 ? "visible" : "hidden"
  }, [])

  const animateTo = useCallback(
    (px: number) => {
      const fg = fgRef.current
      if (!fg) return
      fg.style.transition = `transform ${SNAP_MS}ms ${SNAP_EASE}`
      applyOffset(px)
      window.setTimeout(() => {
        if (fg) fg.style.transition = "none"
      }, SNAP_MS + 10)
    },
    [applyOffset]
  )

  const close = useCallback(() => {
    animateTo(0)
    directionRef.current = "none"
    if (isOpen) onOpenChange(false)
  }, [animateTo, isOpen, onOpenChange])


  const onTouchStart = useCallback(
    (e: TouchEvent<HTMLDivElement>) => {
      if (!enabled) return
      const t = e.touches[0]
      if (!t) return
      const fg = fgRef.current
      if (fg) fg.style.transition = "none"
      touchRef.current = {
        startX: t.clientX,
        startY: t.clientY,
        startOffset: offsetRef.current,
        active: true,
        axis: "none",
        startTime: performance.now(),
        prevX: t.clientX,
        prevT: performance.now(),
      }
    },
    [enabled]
  )

  const onTouchMove = useCallback(
    (e: TouchEvent<HTMLDivElement>) => {
      const tr = touchRef.current
      if (!tr?.active) return
      const t = e.touches[0]
      if (!t) return

      const dx = t.clientX - tr.startX
      const dy = t.clientY - tr.startY

      if (tr.axis === "none") {
        if (Math.abs(dx) < 6 && Math.abs(dy) < 6) return
        if (Math.abs(dy) > Math.abs(dx)) {
          tr.axis = "y"
          tr.active = false
          return
        }
        tr.axis = "x"
      }

      if (tr.axis !== "x") return
      e.preventDefault()

      let raw = tr.startOffset + dx

      // Clamp to panel width (no overswipe)
      if (raw > LEFT_PANEL_PX) raw = LEFT_PANEL_PX
      if (raw < -RIGHT_PANEL_PX) raw = -RIGHT_PANEL_PX

      tr.prevX = t.clientX
      tr.prevT = performance.now()
      applyOffset(raw)
    },
    [applyOffset]
  )

  const onTouchEnd = useCallback(() => {
    const tr = touchRef.current
    touchRef.current = null
    if (!tr?.active || tr.axis !== "x") return

    suppressClickUntilRef.current = performance.now() + 350

    const offset = offsetRef.current
    const elapsed = Math.max(1, performance.now() - tr.startTime)
    const instantVelocity = (tr.prevX - tr.startX) / elapsed

    // If panel was open and user swiped opposite direction → just close
    if (directionRef.current === "right" && offset <= 0) {
      animateTo(0)
      directionRef.current = "none"
      if (isOpen) onOpenChange(false)
      return
    }
    if (directionRef.current === "left" && offset >= 0) {
      animateTo(0)
      directionRef.current = "none"
      if (isOpen) onOpenChange(false)
      return
    }

    // Open/close based on threshold + velocity
    // Closing requires less energy than opening (lower threshold & velocity)
    const closing = isOpen && (
      (directionRef.current === "right" && offset < LEFT_PANEL_PX) ||
      (directionRef.current === "left" && -offset < RIGHT_PANEL_PX)
    )
    const closeThreshold = 0.08
    const closeVelocity = 0.12

    if (offset > 0) {
      if (closing) {
        const shouldStayOpen =
          offset >= LEFT_PANEL_PX * (1 - closeThreshold) &&
          instantVelocity >= -closeVelocity
        if (shouldStayOpen) {
          animateTo(LEFT_PANEL_PX)
        } else {
          animateTo(0)
          directionRef.current = "none"
          onOpenChange(false)
        }
      } else {
        const shouldOpen =
          offset >= LEFT_PANEL_PX * OPEN_THRESHOLD_RATIO ||
          (instantVelocity > OPEN_VELOCITY && offset > 20)
        if (shouldOpen) {
          animateTo(LEFT_PANEL_PX)
          directionRef.current = "right"
          if (!isOpen) onOpenChange(true)
        } else {
          animateTo(0)
          directionRef.current = "none"
          if (isOpen) onOpenChange(false)
        }
      }
    } else if (offset < 0) {
      if (closing) {
        const shouldStayOpen =
          -offset >= RIGHT_PANEL_PX * (1 - closeThreshold) &&
          instantVelocity <= closeVelocity
        if (shouldStayOpen) {
          animateTo(-RIGHT_PANEL_PX)
        } else {
          animateTo(0)
          directionRef.current = "none"
          onOpenChange(false)
        }
      } else {
        const shouldOpen =
          -offset >= RIGHT_PANEL_PX * OPEN_THRESHOLD_RATIO ||
          (instantVelocity < -OPEN_VELOCITY && offset < -20)
        if (shouldOpen) {
          animateTo(-RIGHT_PANEL_PX)
          directionRef.current = "left"
          if (!isOpen) onOpenChange(true)
        } else {
          animateTo(0)
          directionRef.current = "none"
          if (isOpen) onOpenChange(false)
        }
      }
    } else {
      directionRef.current = "none"
      if (isOpen) onOpenChange(false)
    }
  }, [
    animateTo,
    isOpen,
    onOpenChange,
  ])

  const onTouchCancel = useCallback(() => {
    const tr = touchRef.current
    touchRef.current = null
    if (!tr?.active || tr.axis !== "x") return
    animateTo(0)
    directionRef.current = "none"
    if (isOpen) onOpenChange(false)
  }, [animateTo, isOpen, onOpenChange])

  const handleClickCapture = useCallback(
    (e: React.MouseEvent) => {
      if (!enabled) return
      if (performance.now() < suppressClickUntilRef.current) {
        e.preventDefault()
        e.stopPropagation()
        return
      }
      if (offsetRef.current !== 0) {
        e.preventDefault()
        e.stopPropagation()
        close()
      }
    },
    [close, enabled]
  )

  // Close when isOpen flips to false externally (another row opened)
  if (!isOpen && offsetRef.current !== 0 && !touchRef.current?.active) {
    const fg = fgRef.current
    if (fg) {
      fg.style.transition = `transform ${SNAP_MS}ms ${SNAP_EASE}`
      applyOffset(0)
      directionRef.current = "none"
      window.setTimeout(() => {
        if (fg) fg.style.transition = "none"
      }, SNAP_MS + 10)
    }
  }

  if (!enabled) {
    return <div className={className}>{children}</div>
  }

  return (
    <div ref={rowRef} className={cn("relative overflow-hidden", className)} data-swipe-row-id={emailId}>
      {/* Left actions (swipe right to reveal) */}
      <div className="invisible absolute inset-y-0 left-0 flex" ref={leftPanelRef}>
        <button
          type="button"
          aria-label="Mettre en suivi"
          className="flex h-full w-20 shrink-0 flex-col items-center justify-center gap-1 bg-[#f4b400] px-1 text-[11px] font-medium text-white"
          onClick={(e) => { e.stopPropagation(); onStar(); close() }}
        >
          <Star className="size-5 fill-white text-white" strokeWidth={0} />
          <span className="max-w-full truncate text-center">Suivi</span>
        </button>
        <button
          type="button"
          aria-label="Ajouter un libellé"
          className="flex h-full w-20 shrink-0 flex-col items-center justify-center gap-1 bg-[#34a853] px-1 text-[11px] font-medium text-white"
          onClick={(e) => { e.stopPropagation(); onLabel(); close() }}
        >
          <Tag className="size-5 text-white" strokeWidth={1.75} />
          <span className="max-w-full truncate text-center">Libellé</span>
        </button>
        <button
          type="button"
          aria-label="Archiver"
          className="flex h-full w-20 shrink-0 flex-col items-center justify-center gap-1 bg-[#1a73e8] px-1 text-[11px] font-medium text-white"
          onClick={(e) => { e.stopPropagation(); onArchive(); close() }}
        >
          <Archive className="size-5 text-white" strokeWidth={1.75} />
          <span className="max-w-full truncate text-center">Archiver</span>
        </button>
      </div>


      {/* Right actions (swipe left to reveal) */}
      <div className="invisible absolute inset-y-0 right-0 flex" ref={rightPanelRef}>
        <button
          type="button"
          aria-label="Supprimer"
          className="flex h-full w-[100px] shrink-0 flex-col items-center justify-center gap-1 bg-[#d93025] px-2 text-[11px] font-medium text-white"
          onClick={(e) => { e.stopPropagation(); onDelete(); close() }}
        >
          <Trash2 className="size-5 text-white" strokeWidth={1.75} />
          <span className="max-w-full truncate text-center">Supprimer</span>
        </button>
      </div>


      {/* Foreground (row content) */}
      <div
        ref={fgRef}
        className="relative z-1 bg-inherit will-change-transform"
        style={{ transform: "translate3d(0,0,0)" }}
        onTouchStart={onTouchStart}
        onTouchMove={onTouchMove}
        onTouchEnd={onTouchEnd}
        onTouchCancel={onTouchCancel}
        onClickCapture={handleClickCapture}
      >
        {children}
      </div>
    </div>
  )
}

export const MailListSwipeRow = memo(MailListSwipeRowInner)
