import { useState, useMemo } from "react";
import {
  DndContext,
  DragOverlay,
  PointerSensor,
  useSensor,
  useSensors,
  useDroppable,
  useDraggable,
} from "@dnd-kit/core";
import type { DragEndEvent, DragStartEvent } from "@dnd-kit/core";
import { CSS } from "@dnd-kit/utilities";
import { Users, GripVertical, Eye } from "lucide-react";
import { useNavigate } from "react-router-dom";
import { cn } from "@/lib/utils";
import { PHASE_CONFIG, type PhaseOption } from "@/lib/phase-config";

// Phase order for kanban columns
const PHASE_ORDER: PhaseOption[] = ["New", "Demo scheduled", "Contract signed", "Lost"];

interface Contact {
  id?: number;
  firstName?: string;
  lastName?: string;
  mail?: string;
}

interface Deal {
  id?: number;
  name?: string;
  phase?: string;
  notes?: string;
  mainContact?: Contact[];
  createdAt?: string;
  updatedAt?: string;
}

interface KanbanBoardProps {
  deals: Deal[];
  onDealClick: (dealId: number) => void;
  onContactClick: (e: React.MouseEvent, contactId: number) => void;
  onPhaseChange: (dealId: number, newPhase: string) => void;
}

interface KanbanColumnProps {
  phase: PhaseOption;
  deals: Deal[];
  onDealClick: (dealId: number) => void;
  onContactClick: (e: React.MouseEvent, contactId: number) => void;
  isOver?: boolean;
}

interface KanbanCardProps {
  deal: Deal;
  onDealClick: (dealId: number) => void;
  onContactClick: (e: React.MouseEvent, contactId: number) => void;
  isDragging?: boolean;
}

// Droppable Column Component
function KanbanColumn({ phase, deals, onDealClick, onContactClick }: KanbanColumnProps) {
  const { setNodeRef, isOver } = useDroppable({
    id: phase,
  });

  const config = PHASE_CONFIG[phase];
  const Icon = config.icon;

  return (
    <div
      ref={setNodeRef}
      className={cn(
        "flex flex-col w-[280px] flex-shrink-0 rounded-xl border bg-muted/30 transition-colors",
        isOver && "ring-2 ring-primary/50 bg-primary/5"
      )}
    >
      {/* Column Header */}
      <div className={cn("flex items-center gap-2 p-3 border-b", config.bgColor)}>
        <div className={cn("p-1.5 rounded-lg", config.bgColor)}>
          <Icon className={cn("h-4 w-4", config.color)} />
        </div>
        <span className="font-semibold text-sm">{config.label}</span>
        <span className="ml-auto text-xs text-muted-foreground bg-background/50 px-2 py-0.5 rounded-full">
          {deals.length}
        </span>
      </div>

      {/* Cards Container */}
      <div className="flex-1 p-2 space-y-2 overflow-y-auto min-h-[200px] max-h-[calc(100vh-300px)]">
        {deals.length === 0 ? (
          <div className="flex items-center justify-center h-24 text-muted-foreground text-sm opacity-50">
            Drop deals here
          </div>
        ) : (
          deals.map((deal) => (
            <DraggableCard
              key={deal.id}
              deal={deal}
              onDealClick={onDealClick}
              onContactClick={onContactClick}
            />
          ))
        )}
      </div>
    </div>
  );
}

// Draggable Card Wrapper
function DraggableCard({ deal, onDealClick, onContactClick }: KanbanCardProps) {
  const { attributes, listeners, setNodeRef, transform, isDragging } = useDraggable({
    id: deal.id!,
    data: { deal },
  });

  const style = {
    transform: CSS.Translate.toString(transform),
    opacity: isDragging ? 0.5 : 1,
  };

  return (
    <div ref={setNodeRef} style={style}>
      <KanbanCard
        deal={deal}
        onDealClick={onDealClick}
        onContactClick={onContactClick}
        isDragging={isDragging}
        dragHandleProps={{ ...attributes, ...listeners }}
      />
    </div>
  );
}

// Card Component
function KanbanCard({
  deal,
  onDealClick,
  onContactClick,
  isDragging,
  dragHandleProps,
}: KanbanCardProps & { dragHandleProps?: Record<string, unknown> }) {
  const navigate = useNavigate();
  const contact = deal.mainContact?.[0];

  const formatContactName = (contact: Contact): string => {
    const parts = [contact.firstName, contact.lastName].filter(Boolean);
    return parts.join(" ") || "Unknown";
  };

  const formatDate = (dateStr?: string) => {
    if (!dateStr) return "";
    return new Date(dateStr).toLocaleDateString("en-US", {
      month: "short",
      day: "numeric",
    });
  };

  return (
    <div
      className={cn(
        "bg-background rounded-lg border shadow-sm p-3 cursor-pointer hover:shadow-md hover:border-primary/30 transition-all group",
        isDragging && "shadow-lg ring-2 ring-primary/30"
      )}
      onClick={() => deal.id && onDealClick(deal.id)}
    >
      <div className="flex items-start gap-2">
        {/* Drag Handle */}
        <div
          {...dragHandleProps}
          className="opacity-0 group-hover:opacity-100 transition-opacity cursor-grab active:cursor-grabbing mt-0.5 -ml-1"
          onClick={(e) => e.stopPropagation()}
        >
          <GripVertical className="h-4 w-4 text-muted-foreground" />
        </div>

        <div className="flex-1 min-w-0">
          {/* Deal Name */}
          <div className="flex items-center justify-between gap-2">
            <h4 className="font-medium text-sm truncate">{deal.name || "Untitled Deal"}</h4>
            {/* View Deal Page Button */}
            <button
              onClick={(e) => {
                e.stopPropagation();
                if (deal.id) navigate(`/deals/${deal.id}`);
              }}
              className="opacity-0 group-hover:opacity-100 transition-opacity p-1 rounded hover:bg-muted"
              title="View deal details"
            >
              <Eye className="h-3.5 w-3.5 text-muted-foreground" />
            </button>
          </div>

          {/* Contact */}
          {contact?.id && (
            <button
              onClick={(e) => {
                e.stopPropagation();
                onContactClick(e, contact.id!);
              }}
              className="inline-flex items-center gap-1 mt-2 px-2 py-0.5 rounded bg-blue-500/10 text-blue-600 hover:bg-blue-500/20 transition-colors text-xs"
            >
              <Users className="h-3 w-3" />
              <span className="truncate max-w-[120px]">{formatContactName(contact)}</span>
            </button>
          )}

          {/* Date */}
          {deal.createdAt && (
            <p className="text-xs text-muted-foreground mt-2">
              {formatDate(deal.createdAt)}
            </p>
          )}
        </div>
      </div>
    </div>
  );
}

// Overlay Card (shown while dragging)
function DragOverlayCard({ deal, onDealClick, onContactClick }: KanbanCardProps) {
  return (
    <div className="w-[280px]">
      <KanbanCard
        deal={deal}
        onDealClick={onDealClick}
        onContactClick={onContactClick}
        isDragging={true}
      />
    </div>
  );
}

// Main Kanban Board Component
export function KanbanBoard({ deals, onDealClick, onContactClick, onPhaseChange }: KanbanBoardProps) {
  const [activeDeal, setActiveDeal] = useState<Deal | null>(null);
  // Track optimistic phase changes locally
  const [optimisticPhases, setOptimisticPhases] = useState<Record<number, string>>({});

  // Configure sensors - require 8px movement before drag starts
  const sensors = useSensors(
    useSensor(PointerSensor, {
      activationConstraint: {
        distance: 8,
      },
    })
  );

  // Apply optimistic updates to deals
  const dealsWithOptimisticUpdates = useMemo(() => {
    return deals.map((deal) => {
      if (deal.id && optimisticPhases[deal.id]) {
        return { ...deal, phase: optimisticPhases[deal.id] };
      }
      return deal;
    });
  }, [deals, optimisticPhases]);

  // Clear optimistic updates when server data matches
  useMemo(() => {
    const newOptimistic: Record<number, string> = {};
    for (const [idStr, phase] of Object.entries(optimisticPhases)) {
      const id = Number(idStr);
      const deal = deals.find((d) => d.id === id);
      // Keep optimistic update only if server hasn't caught up yet
      if (deal && deal.phase !== phase) {
        newOptimistic[id] = phase;
      }
    }
    // Only update if there's a difference
    if (Object.keys(newOptimistic).length !== Object.keys(optimisticPhases).length) {
      setOptimisticPhases(newOptimistic);
    }
  }, [deals, optimisticPhases]);

  // Group deals by phase
  const dealsByPhase = useMemo(() => {
    const grouped: Record<string, Deal[]> = {};
    
    // Initialize all phases with empty arrays
    PHASE_ORDER.forEach((phase) => {
      grouped[phase] = [];
    });

    // Group deals (with optimistic updates applied)
    dealsWithOptimisticUpdates.forEach((deal) => {
      const phase = deal.phase || "New";
      if (grouped[phase]) {
        grouped[phase].push(deal);
      } else {
        // If phase doesn't exist in our order, default to "New"
        grouped["New"].push(deal);
      }
    });

    return grouped;
  }, [dealsWithOptimisticUpdates]);

  const handleDragStart = (event: DragStartEvent) => {
    const { active } = event;
    const deal = dealsWithOptimisticUpdates.find((d) => d.id === active.id);
    if (deal) {
      setActiveDeal(deal);
    }
  };

  const handleDragEnd = (event: DragEndEvent) => {
    const { active, over } = event;
    setActiveDeal(null);

    if (!over) return;

    const dealId = active.id as number;
    const newPhase = over.id as string;

    // Find the deal and check if phase actually changed
    const deal = dealsWithOptimisticUpdates.find((d) => d.id === dealId);
    if (deal && deal.phase !== newPhase) {
      // Apply optimistic update immediately
      setOptimisticPhases((prev) => ({ ...prev, [dealId]: newPhase }));
      // Then trigger the actual mutation
      onPhaseChange(dealId, newPhase);
    }
  };

  return (
    <DndContext
      sensors={sensors}
      onDragStart={handleDragStart}
      onDragEnd={handleDragEnd}
    >
      <div className="inline-flex gap-4 pb-4 h-full">
        {PHASE_ORDER.map((phase) => (
          <KanbanColumn
            key={phase}
            phase={phase}
            deals={dealsByPhase[phase] || []}
            onDealClick={onDealClick}
            onContactClick={onContactClick}
          />
        ))}
      </div>

      <DragOverlay>
        {activeDeal ? (
          <DragOverlayCard
            deal={activeDeal}
            onDealClick={onDealClick}
            onContactClick={onContactClick}
          />
        ) : null}
      </DragOverlay>
    </DndContext>
  );
}
