"use client"

import * as React from "react"
import { Deal, Stage } from "./types"
import { Button } from "@/components/ui/button"
import { cn } from "@/lib/utils"
import { Skeleton } from "@/components/ui/skeleton"
import { Can } from "@/components/providers/ability-provider"
import { PencilLine, Trash2, Eye, Calendar, UserPlus, Loader2, ClipboardList, Target, Briefcase, Timer } from "lucide-react"
import { dealsApi, useConvertDealToCustomerMutation } from "@/api/rtk/deals-api"
import { useConvertBusinessDealToCustomerMutation } from "@/api/rtk/business-deals-api"
import { useGetProfileQuery } from "@/api/rtk/auth-api"
import { toast } from "sonner"
import { useRouter } from "next/navigation"
import { useQueryClient } from "@tanstack/react-query"
import { invalidateLeadsBoardColumnsTouchingStages } from "@/features/leads/api/invalidate-leads-board-columns"
import { leadsKeys } from "@/features/leads/api/query-keys"
import { useAppDispatch } from "@/store/hooks"
import { businessDealsBoardKeys } from "@/features/business-deals/query-keys"
import { getPermissions, hasPermission } from "@/lib/permissions"
import { resolveTeamDisplayName } from "@/lib/deal-display"
import { useSession } from "next-auth/react"
import type { PermissionSource } from "@/api/permissions/types"

interface DealCardProps {
    deal: Deal
    stages?: Stage[]
    isAlreadyCustomer?: boolean
    onOpen: (deal: Deal) => void
    onEdit: (deal: Deal) => void
    onDelete: (id: string) => void
    onAssignTask?: (deal: Deal) => void
    /** CASL subject for permission checks — "lead" on the Leads page, "deal" on the Deals page */
    canSubject?: "lead" | "deal"
    /**
     * Kanban only: one board-level profile read; skips `useGetProfileQuery` per card so
     * @hello-pangea/dnd drag ticks do not multiply RTK subscriptions / re-renders.
     */
    kanbanPermissions?: { source: unknown }
    teams?: Array<{ id: string; name: string }>
    /** Kanban: resolve `timelineIntentId` when the board payload omits nested `timelineIntent`. */
    timelineIntents?: Array<{ id: string; name: string }>
    /** Kanban drag shell: grab cursor on card body (overrides default pointer). */
    kanbanDraggable?: boolean
    /** @dnd-kit — ref + listeners must live on the same node as the press target. */
    kanbanNodeRef?: (node: HTMLElement | null) => void
    kanbanDragAttributes?: React.HTMLAttributes<HTMLDivElement>
    kanbanDragListeners?: {
        onPointerDown?: (e: React.PointerEvent<HTMLDivElement>) => void
        onKeyDown?: (e: React.KeyboardEvent<HTMLDivElement>) => void
    }
}

function isDealCardInteractiveTarget(target: EventTarget | null): boolean {
    if (!(target instanceof Element)) return false
    // Do not use [role='button'] — @dnd-kit sets role="button" on the draggable card root,
    // which would block every pointerdown and leave only onClick (detail page).
    return Boolean(
        target.closest(
            "button, a, input, textarea, select, label, [data-no-dnd]",
        ),
    )
}

function hasExactPermission(
    source: PermissionSource,
    action: string,
    resource: string,
): boolean {
    const a = action.trim().toUpperCase()
    const r = resource.trim().toUpperCase()
    return getPermissions(source).some((p) => {
        const pa = String(p?.action ?? "").trim().toUpperCase()
        const pr = String(p?.resource ?? "").trim().toUpperCase()
        return pa === a && (pr === r || pr === "ALL")
    })
}

const STATUS_COLORS: Record<string, { bg: string; text: string }> = {
    "Connected & Talking": { bg: "bg-[#edf9f0]", text: "text-[#16A34A]" },
    "Not Interested": { bg: "bg-[#fdf0ed]", text: "text-[#c10007]" },
    "VM & DVM - No Contact": { bg: "bg-[#faf4e4]", text: "text-[#d09f47]" },
    "Lost": { bg: "bg-[#fdf0ed]", text: "text-[#c10007]" },
    "Email Sent": { bg: "bg-[#eef0ff]", text: "text-[#1447e6]" },
    "Callback Scheduled": { bg: "bg-[#faf4e4]", text: "text-[#d09f47]" },
    "Invalid": { bg: "bg-[#f1f5f9]", text: "text-[#64748B]" },
    "Paid": { bg: "bg-[#edf9f0]", text: "text-[#16A34A]" },
    "Acquired": { bg: "bg-[#edf9f0]", text: "text-[#15803D]" },
    "Need to be reverted": { bg: "bg-[#faf4e4]", text: "text-[#d09f47]" },
    "Unqualified": { bg: "bg-[#f1f5f9]", text: "text-[#64748B]" },
    "VM - Still Trying": { bg: "bg-[#faf4e4]", text: "text-[#d09f47]" },
}

const CHANNEL_COLORS: Record<string, { bg: string; text: string }> = {
    "PPC": { bg: "bg-indigo-50", text: "text-indigo-600" },
    "BARK": { bg: "bg-rose-50", text: "text-rose-600" },
    "Referral": { bg: "bg-emerald-50", text: "text-emerald-600" },
    "Thumbtack": { bg: "bg-amber-50", text: "text-amber-600" },
    "Facebook": { bg: "bg-blue-50", text: "text-blue-600" },
    "Instagram": { bg: "bg-pink-50", text: "text-pink-600" },
    "Google": { bg: "bg-red-50", text: "text-red-600" },
    "Organic": { bg: "bg-slate-50", text: "text-slate-600" },
}

function formatCost(val?: number) {
    if (!val) return null
    if (val >= 1_000_000) return `$${(val / 1_000_000).toFixed(1)}M`
    if (val >= 1_000) return `$${(val / 1_000).toFixed(1)}K`
    return `$${val.toFixed(0)}`
}

/** Backend + add-deal use MM/DD/YYYY (UTC calendar). Parse explicitly so month/year match that string (avoids off-by-one from ambiguous Date.parse or wrong tuple destructuring). */
function formatCreatedMonthYear(createdDate: string): string {
    const s = createdDate.trim()
    const parts = s.split("/").map((p) => p.trim())
    const opts: Intl.DateTimeFormatOptions = { month: "short", year: "numeric", timeZone: "UTC" }

    if (parts.length === 3) {
        const month = parseInt(parts[0]!, 10)
        const day = parseInt(parts[1]!, 10)
        const year = parseInt(parts[2]!, 10)
        if (month >= 1 && month <= 12 && day >= 1 && day <= 31 && year >= 1900 && year < 2100) {
            return new Date(Date.UTC(year, month - 1, day)).toLocaleDateString(undefined, opts)
        }
    }
    if (parts.length === 2) {
        const month = parseInt(parts[0]!, 10)
        const year = parseInt(parts[1]!, 10)
        if (month >= 1 && month <= 12 && year >= 1900 && year < 2100) {
            return new Date(Date.UTC(year, month - 1, 1)).toLocaleDateString(undefined, opts)
        }
    }

    const d = new Date(s)
    if (!Number.isNaN(d.getTime())) {
        return d.toLocaleDateString(undefined, { month: "short", year: "numeric" })
    }
    return "—"
}

function isClosedWonStage(deal: Deal, stages?: Stage[]): boolean {
    if (deal.stage === "closed_won") return true
    if (!stages?.length || !deal.stage) return false
    const stage = stages.find(s => s.id === deal.stage)
    return Boolean(stage && String(stage.name || "").toLowerCase().includes("closed won"))
}

function isScopingStage(deal: Deal, stages?: Stage[]): boolean {
    if (deal.stage === "scoping") return true
    if (!stages?.length || !deal.stage) return false
    const stage = stages.find(s => s.id === deal.stage)
    return Boolean(stage && (
        String(stage.id).toLowerCase().includes("scoping") ||
        String(stage.name || "").toLowerCase().includes("scoping")
    ))
}

/** Lead notes (`DealNote`), business row `notes`, or board-only `dealNoteCount` from API. */
function resolveTimelineIntentLabel(
    deal: Deal,
    timelineIntents?: Array<{ id: string; name: string }>,
): string | null {
    const nested = deal.timelineIntent
    if (nested) {
        if (typeof nested === "object" && nested.name?.trim()) {
            return nested.name.trim()
        }
        if (typeof nested === "string" && nested.trim()) {
            return nested.trim()
        }
    }
    const id = deal.timelineIntentId?.trim()
    if (!id || !timelineIntents?.length) return null
    const match = timelineIntents.find((t) => t.id === id)
    return match?.name?.trim() || null
}

function resolveServiceLabel(deal: Deal): string | null {
    const fromName = deal.serviceName?.trim()
    if (fromName) return fromName
    if (typeof deal.service === "object" && deal.service?.name?.trim()) {
        return deal.service.name.trim()
    }
    if (typeof deal.service === "string" && deal.service.trim()) {
        return deal.service.trim()
    }
    return null
}

function dealHasNotes(deal: Deal): boolean {
    if ((deal.dealNotes?.length ?? 0) > 0) return true
    const n = typeof deal.dealNoteCount === "number" ? deal.dealNoteCount : 0
    if (n > 0) return true
    const text = typeof deal.notes === "string" ? deal.notes.trim() : ""
    return text.length > 0
}

export function DealCardSkeleton() {
    return (
        <div className="backdrop-blur-[15px] bg-[rgba(244,246,255,0.4)] border border-white rounded-[14px] shadow-[0px_2px_15px_0px_rgba(0,0,0,0.1)] p-[14px] flex flex-col gap-[10px]">
            <div className="flex items-start justify-between">
                <Skeleton className="h-4 w-3/4 rounded-md" />
                <Skeleton className="h-4 w-12 rounded-md" />
            </div>
            <div className="flex flex-wrap gap-[5px]">
                <Skeleton className="h-[17px] w-14 rounded-[10px]" />
                <Skeleton className="h-[17px] w-16 rounded-[10px]" />
                <Skeleton className="h-[17px] w-12 rounded-[10px]" />
            </div>
            <div className="flex items-center justify-between pt-1">
                <div className="flex items-center gap-[3px]">
                    <Skeleton className="size-[21px] rounded-full" />
                    <Skeleton className="h-3 w-16 rounded-md" />
                </div>
                <div className="flex items-center gap-[3px]">
                    <Skeleton className="size-3 rounded-full" />
                    <Skeleton className="h-3 w-12 rounded-md" />
                </div>
            </div>
        </div>
    )
}

function DealCardInner({
    deal,
    stages,
    onOpen,
    onEdit,
    onDelete,
    onAssignTask,
    isAlreadyCustomer = false,
    kanbanPermissions,
    kanbanDraggable,
    kanbanNodeRef,
    kanbanDragAttributes,
    kanbanDragListeners,
    canSubject = "deal",
    teams,
    timelineIntents,
}: DealCardProps) {
    const router = useRouter()
    const queryClient = useQueryClient()
    const dispatch = useAppDispatch()
    const pointerStartRef = React.useRef<{ x: number; y: number } | null>(null)
    const dragGestureRef = React.useRef(false)
    const { data: session } = useSession()
    const { data: profile } = useGetProfileQuery(undefined, {
        skip: kanbanPermissions != null,
    })
    const permissionSource =
        kanbanPermissions?.source ??
        (session as { backendUser?: unknown } | null)?.backendUser ??
        profile

    const canCreateCustomer = hasPermission(permissionSource, ["CREATE", "UPDATE"], "CUSTOMER")
    const deleteResource = canSubject === "lead" ? "LEAD" : "DEAL"
    const canDeleteCard = hasExactPermission(permissionSource, "DELETE", deleteResource)


    const [convertToCustomer] = useConvertDealToCustomerMutation()
    const [convertBusinessDealToCustomer] = useConvertBusinessDealToCustomerMutation()
    const [isConvertingThis, setIsConvertingThis] = React.useState(false)
    const [convertedLocally, setConvertedLocally] = React.useState(false)

    React.useEffect(() => {
        setIsConvertingThis(false)
        setConvertedLocally(false)
    }, [deal.id])

    React.useEffect(() => {
        if (isAlreadyCustomer || deal.customerId?.trim()) {
            setConvertedLocally(true)
        }
    }, [isAlreadyCustomer, deal.customerId])

    const alreadyCustomer =
        isAlreadyCustomer ||
        convertedLocally ||
        Boolean(deal.customerId?.trim())

    const isClosedWon = isClosedWonStage(deal, stages)
    const isScoping = isScopingStage(deal, stages)

    const handleMoveToCustomer = async (e: React.MouseEvent) => {
        e.stopPropagation()
        if (alreadyCustomer) {
            toast.info("Customer already moved. Opening customers…")
            router.push("/customers")
            return
        }
        if (isConvertingThis) return

        setIsConvertingThis(true)
        try {
            if (deal.isBusinessDeal) {
                await convertBusinessDealToCustomer(deal.id).unwrap()
            } else {
                await convertToCustomer(deal.id).unwrap()
            }
            setConvertedLocally(true)

            if (!deal.isBusinessDeal) {
                dispatch(
                    dealsApi.util.updateQueryData(
                        "getConvertedDealIds",
                        undefined,
                        (draft) => {
                            if (!draft.includes(deal.id)) {
                                draft.push(deal.id)
                            }
                        },
                    ),
                )
            }

            toast.success("Successfully converted to customer")

            if (deal.isBusinessDeal) {
                queryClient.invalidateQueries({ queryKey: businessDealsBoardKeys.all })
            } else {
                queryClient.invalidateQueries({ queryKey: leadsKeys.all })
                if (deal.stage) {
                    invalidateLeadsBoardColumnsTouchingStages(queryClient, [deal.stage])
                }
            }

            if (typeof window !== "undefined") {
                if (deal.stage) {
                    window.dispatchEvent(new CustomEvent(`kanban-refresh-${deal.stage}`))
                }
                window.dispatchEvent(new CustomEvent("kanban-refresh-counts"))
            }
        } catch (error: unknown) {
            const err = error as { data?: { message?: string } }
            const msg = err?.data?.message ?? ""
            if (msg.includes("already been converted") || msg.includes("already converted")) {
                setConvertedLocally(true)
                if (!deal.isBusinessDeal) {
                    dispatch(
                        dealsApi.util.updateQueryData(
                            "getConvertedDealIds",
                            undefined,
                            (draft) => {
                                if (!draft.includes(deal.id)) {
                                    draft.push(deal.id)
                                }
                            },
                        ),
                    )
                }
                toast.info("Customer already moved.")
                if (deal.isBusinessDeal) {
                    queryClient.invalidateQueries({ queryKey: businessDealsBoardKeys.all })
                } else {
                    queryClient.invalidateQueries({ queryKey: leadsKeys.all })
                    if (deal.stage) {
                        invalidateLeadsBoardColumnsTouchingStages(queryClient, [deal.stage])
                    }
                }
                if (typeof window !== "undefined" && deal.stage) {
                    window.dispatchEvent(new CustomEvent(`kanban-refresh-${deal.stage}`))
                }
                return
            }
            toast.error(msg || "Failed to move to customer")
        } finally {
            setIsConvertingThis(false)
        }
    }

    const ownerLabel = deal.owner?.name || deal.createdBy
    const ownerInitials = ownerLabel
        ? ownerLabel.split(/\s+/).map(w => w[0]).join('').slice(0, 2).toUpperCase()
        : null

    const budgetFormatted = formatCost(deal.budget)
    const teamDisplayName = resolveTeamDisplayName(deal.team, teams ?? [])

    const channelName = typeof deal.leadChannel === "object" ? deal.leadChannel?.name : deal.leadChannel
    const serviceLabel = resolveServiceLabel(deal)
    const timelineIntentLabel = resolveTimelineIntentLabel(deal, timelineIntents)
    const statusCfg = deal.leadStatus ? (STATUS_COLORS[deal.leadStatus] || { bg: "bg-[#eef0ff]", text: "text-[#1447e6]" }) : null
    const channelCfg = channelName ? (CHANNEL_COLORS[channelName] || { bg: "bg-gray-50", text: "text-gray-600" }) : null

    const pipelineLeadDisplayId = deal.leadId?.trim() || ""
    const recordIdLabel =
        canSubject === "lead" || (deal.isBusinessDeal && pipelineLeadDisplayId)
            ? "Lead ID"
            : "Deal ID"
    const recordIdValue =
        canSubject === "lead"
            ? (pipelineLeadDisplayId || deal.id)
            : deal.isBusinessDeal
              ? pipelineLeadDisplayId
              : deal.id

    const handleKanbanPointerDown = (e: React.PointerEvent<HTMLDivElement>) => {
        if (isDealCardInteractiveTarget(e.target)) {
            e.stopPropagation()
            pointerStartRef.current = null
            return
        }
        pointerStartRef.current = { x: e.clientX, y: e.clientY }
        dragGestureRef.current = false
        kanbanDragListeners?.onPointerDown?.(e)
    }

    const handleKanbanPointerMove = (e: React.PointerEvent<HTMLDivElement>) => {
        const start = pointerStartRef.current
        if (!kanbanDraggable || !start) return
        if (Math.hypot(e.clientX - start.x, e.clientY - start.y) > 6) {
            dragGestureRef.current = true
        }
    }

    const handleCardClick = (e: React.MouseEvent<HTMLDivElement>) => {
        if (deal.isOptimistic) return
        if (kanbanDraggable && dragGestureRef.current) {
            e.preventDefault()
            e.stopPropagation()
            dragGestureRef.current = false
            pointerStartRef.current = null
            return
        }
        pointerStartRef.current = null
        onOpen(deal)
    }

    return (
        <div
            ref={kanbanDraggable ? kanbanNodeRef : undefined}
            {...(kanbanDraggable ? kanbanDragAttributes : {})}
            className={cn(
                "group relative bg-[#f4f6ff]/60 border border-white rounded-[14px] shadow-[0px_2px_15px_0px_rgba(0,0,0,0.1)] p-[14px] flex flex-col gap-[10px] transition-all duration-200 [contain:content]",
                deal.isOptimistic
                    ? "opacity-60 cursor-wait pointer-events-none"
                    : kanbanDraggable
                      ? "cursor-grab active:cursor-grabbing hover:-translate-y-0.5"
                      : kanbanPermissions != null
                        ? "cursor-default hover:-translate-y-0.5"
                        : "cursor-pointer hover:-translate-y-0.5"
            )}
            onClick={handleCardClick}
            onPointerDown={kanbanDraggable ? handleKanbanPointerDown : (e) => {
                if (isDealCardInteractiveTarget(e.target)) {
                    e.stopPropagation()
                }
            }}
            onPointerMove={kanbanDraggable ? handleKanbanPointerMove : undefined}
            onKeyDown={kanbanDraggable ? kanbanDragListeners?.onKeyDown : undefined}
            style={kanbanDraggable ? { touchAction: "none" } : undefined}
        >
            {/* Optimistic indicator */}
            {deal.isOptimistic && (
                <div className="absolute top-2 right-2 flex items-center gap-1.5 px-2 py-0.5 bg-accent/10 border border-accent/20 rounded-full z-20">
                    <Loader2 size={10} className="animate-spin text-accent" />
                    <span className="text-[9px] font-bold text-accent uppercase tracking-wider">Saving...</span>
                </div>
            )}

            {/* Actions overlay */}
            {!deal.isOptimistic && (
                <div
                    className="absolute top-2 right-2 flex items-center gap-1 opacity-0 group-hover:opacity-100 transition-all duration-200 z-10 pointer-events-none group-hover:pointer-events-auto"
                    data-no-dnd
                    onPointerDown={(e) => e.stopPropagation()}
                >
                    <Can action="view" subject={canSubject}>
                        <Button variant="floating" size="iconDeal" onClick={(e) => { e.stopPropagation(); onOpen(deal) }}>
                            <Eye size={11} />
                        </Button>
                    </Can>
                    <Can action="update" subject={canSubject}>
                        <Button variant="floating" size="iconDeal" onClick={(e) => { e.stopPropagation(); onEdit(deal) }}>
                            <PencilLine size={11} />
                        </Button>
                    </Can>
                    {!isClosedWon && canDeleteCard && (
                            <Button variant="floatingDanger" size="iconDeal" onClick={(e) => { e.stopPropagation(); onDelete(deal.id) }}>
                                <Trash2 size={11} />
                            </Button>
                    )}
                </div>
            )}

            {/* Row 1: Name + Cost */}
            <div className="flex items-start justify-between whitespace-nowrap">
                <div className="min-w-0 flex-1 pr-4">
                    <p className="text-xs font-semibold text-[#101828] line-clamp-1 leading-[17px]">
                        {deal.customerName || "Unnamed Lead"}
                    </p>
                    {deal.companyName ? (
                        <p className="text-[10px] font-medium text-[#6a7282] line-clamp-1 mt-0.5">{deal.companyName}</p>
                    ) : null}
                    {recordIdValue ? (
                        <p
                            className="text-[10px] font-medium text-[#9ca3af] line-clamp-1 mt-0.5 tabular-nums"
                            title={`${recordIdLabel}: ${recordIdValue}`}
                        >
                            {recordIdValue}
                        </p>
                    ) : null}
                </div>
                <div className="flex flex-col items-end shrink-0 gap-0.5">
                    {budgetFormatted && (
                        <p className="text-[12px] font-semibold text-[#4f39f6] leading-[17px] tabular-nums">
                            {budgetFormatted}
                        </p>
                    )}
                </div>
            </div>

            {/* Row 2: Tags — Figma: h-[17px] px-[7px] py-[2px] rounded-[10px] 10px medium */}
            <div className="flex flex-wrap gap-[5px] items-center">
                {!!deal.customerId && (
                    <div className="h-[17px] flex items-center px-[7px] rounded-[10px] bg-emerald-100">
                        <span className="text-[10px] font-medium text-emerald-700 whitespace-nowrap leading-none">Already a customer</span>
                    </div>
                )}
                {alreadyCustomer && !deal.customerId && !deal.isBusinessDeal && (
                    <div className="h-[17px] flex items-center px-[7px] rounded-[10px] bg-[#eef0ff] border border-[#c7d2fe]">
                        <span className="text-[10px] font-medium text-[#4338ca] whitespace-nowrap leading-none">Already Deal</span>
                    </div>
                )}
                {deal.isBusinessDeal && deal.linkedLeadPk?.trim() && (
                    <div className="h-[17px] flex items-center px-[7px] rounded-[10px] bg-[#eef0ff] border border-[#c7d2fe]">
                        <span className="text-[10px] font-medium text-[#4338ca] whitespace-nowrap leading-none">Already Deal</span>
                    </div>
                )}
                {dealHasNotes(deal) && (
                    <div className="h-[17px] flex items-center px-[7px] rounded-[10px] bg-[#f1f5f9] border border-[#e2e8f0]">
                        <span className="text-[10px] font-medium text-[#475569] whitespace-nowrap leading-none">Notes</span>
                    </div>
                )}
                {deal?.brand && (
                    <div className="h-[17px] flex items-center px-[7px] rounded-[10px] bg-[#eef0ff]">
                        <span className="text-[10px] font-medium text-[#1447e6] whitespace-nowrap leading-none">{deal.brand}</span>
                    </div>
                )}
                {serviceLabel && (
                    <div className="h-[17px] flex items-center gap-1 px-[7px] rounded-[10px] bg-teal-50 border border-teal-100 max-w-full">
                        <Briefcase size={10} className="shrink-0 text-teal-700" />
                        <span className="text-[10px] font-medium text-teal-800 whitespace-nowrap leading-none truncate max-w-[140px]">
                            {serviceLabel}
                        </span>
                    </div>
                )}
                {statusCfg && (
                    <div className={cn("h-[17px] flex items-center px-[7px] rounded-[10px]", statusCfg.bg)}>
                        <span className={cn("text-[10px] font-medium whitespace-nowrap leading-none", statusCfg.text)}>{deal.leadStatus}</span>
                    </div>
                )}
                {channelCfg && (
                    <div className={cn("h-[17px] flex items-center gap-1 px-[7px] rounded-[10px] border border-transparent hover:border-current/10 transition-colors", channelCfg.bg)}>
                        <Target size={10} className={cn("shrink-0", channelCfg.text)} />
                        <span className={cn("text-[10px] font-bold whitespace-nowrap leading-none", channelCfg.text)}>{channelName}</span>
                    </div>
                )}
                {timelineIntentLabel && (
                    <div
                        className="h-[17px] flex items-center gap-1 px-[7px] rounded-[10px] bg-purple-50 border border-purple-100 max-w-full"
                        title={timelineIntentLabel}
                    >
                        <Timer size={10} className="shrink-0 text-purple-700" />
                        <span className="text-[10px] font-medium text-purple-700 whitespace-nowrap leading-none truncate max-w-[140px]">
                            {timelineIntentLabel}
                        </span>
                    </div>
                )}
                {teamDisplayName && (
                    <div className="h-[17px] flex items-center px-[7px] rounded-[10px] bg-[#f1f5f9] border border-[#e2e8f0]">
                        <span className="text-[10px] font-medium text-[#475569] whitespace-nowrap leading-none">{teamDisplayName}</span>
                    </div>
                )}
            </div>

            {/* Row 3: Owner + Date */}
            <div className="flex items-center justify-between">
                {ownerInitials ? (
                    <div className="flex items-center gap-[3px]">
                        <div className="size-[21px] rounded-full bg-[#f1ecf8] flex items-center justify-center">
                            <span className="text-[8px] font-bold text-[#7465db]">{ownerInitials}</span>
                        </div>
                        <span className="text-[10px] text-[#6a7282]">{ownerLabel!.split(' ')[0]}</span>
                    </div>
                ) : (
                    <div />
                )}
                {deal.createdDate && (
                    <div className="flex items-center gap-[3px] text-[10px] text-[#6a7282]">
                        <Calendar size={10} className="shrink-0" />
                        <span>{formatCreatedMonthYear(deal.createdDate)}</span>
                    </div>
                )}
            </div>

            {/* Assign Task (Scoping Stage) — lead pipeline only */}
            {isScoping && !deal.isBusinessDeal && (
                <div className="pt-2 border-t border-white/60 mt-0.5">
                    <Button
                        variant="dealCardAssignTask"
                        onClick={(e) => {
                            e.stopPropagation()
                            onAssignTask?.(deal)
                        }}
                    >
                        <ClipboardList className="h-3.5 w-3.5" />
                        Assign task
                    </Button>
                </div>
            )}

            {/* Move to Customer (Closed Won) — leads use /deals/.../convert; business deals use /business-deals/... */}
            {canCreateCustomer && isClosedWon && (
                <div className="pt-2 border-t border-white/60 mt-0.5">
                    <Button
                        variant={alreadyCustomer ? "dealCardCustomerView" : "dealCardCustomerConvert"}
                        onClick={handleMoveToCustomer}
                        disabled={isConvertingThis}
                    >
                        {isConvertingThis ? (
                            <Loader2 className="h-3.5 w-3.5 animate-spin" />
                        ) : alreadyCustomer ? (
                            <Eye className="h-3.5 w-3.5" />
                        ) : (
                            <UserPlus className="h-3.5 w-3.5" />
                        )}
                        {isConvertingThis
                            ? "Moving…"
                            : alreadyCustomer
                              ? "View customer"
                              : "Move to customer"}
                    </Button>
                </div>
            )}
        </div>
    )
}

function dealCardPropsEqual(prev: DealCardProps, next: DealCardProps) {
    return (
        prev.deal === next.deal &&
        prev.stages === next.stages &&
        prev.isAlreadyCustomer === next.isAlreadyCustomer &&
        prev.onOpen === next.onOpen &&
        prev.onEdit === next.onEdit &&
        prev.onDelete === next.onDelete &&
        prev.onAssignTask === next.onAssignTask &&
        prev.kanbanPermissions === next.kanbanPermissions &&
        prev.kanbanDraggable === next.kanbanDraggable &&
        prev.kanbanNodeRef === next.kanbanNodeRef &&
        prev.kanbanDragAttributes === next.kanbanDragAttributes &&
        prev.kanbanDragListeners === next.kanbanDragListeners &&
        prev.canSubject === next.canSubject &&
        prev.teams === next.teams &&
        prev.timelineIntents === next.timelineIntents
    )
}

/** Memoized so @hello-pangea/dnd drag updates do not re-run every card’s hooks each frame. */
export const DealCard = React.memo(DealCardInner, dealCardPropsEqual)
DealCard.displayName = "DealCard"
