import { useCallback, useEffect, useMemo, useRef, useState } from "react";

import { cn } from "../../lib/utils";
import type { Host, ManagedSource } from "../../types";
import { toast } from "../ui/toast";

type DropTarget =
  | { kind: "root" }
  | { kind: "group"; path: string };

interface UseVaultGroupDragHandlersOptions {
  hosts: Host[];
  managedSources: ManagedSource[];
  onUnmanageSource?: (sourceId: string) => void;
  onUpdateHosts: (hosts: Host[]) => void;
  onUpdateManagedSources: (sources: ManagedSource[]) => void;
  t: (key: string, values?: Record<string, unknown>) => string;
}

export function useVaultGroupDragHandlers({
  hosts,
  managedSources,
  onUnmanageSource,
  onUpdateHosts,
  onUpdateManagedSources,
  t,
}: UseVaultGroupDragHandlersOptions) {
  const [dragOverDropTarget, setDragOverDropTarget] = useState<DropTarget | null>(null);
  
  const [confirmedDropTarget, setConfirmedDropTarget] = useState<DropTarget | null>(null);
  
  const dropTargetPulseTimeoutRef = useRef<number | null>(null);
  
  useEffect(() => {
      return () => {
        if (dropTargetPulseTimeoutRef.current !== null) {
          window.clearTimeout(dropTargetPulseTimeoutRef.current);
        }
      };
    }, []);
  
  const managedGroupPaths = useMemo(() => {
      return new Set(managedSources.map(s => s.groupName));
    }, [managedSources]);
  
  const isSameDropTarget = useCallback((a: DropTarget | null, b: DropTarget | null) => {
      if (!a || !b) return a === b;
      if (a.kind !== b.kind) return false;
      if (a.kind === "root") return true;
      if (b.kind === "root") return false;
      return a.path === b.path;
    }, []);
  
  const pulseDropTarget = useCallback((target: DropTarget) => {
      setConfirmedDropTarget(target);
      if (dropTargetPulseTimeoutRef.current !== null) {
        window.clearTimeout(dropTargetPulseTimeoutRef.current);
      }
      dropTargetPulseTimeoutRef.current = window.setTimeout(() => {
        setConfirmedDropTarget((current) => (isSameDropTarget(current, target) ? null : current));
        dropTargetPulseTimeoutRef.current = null;
      }, 900);
    }, [isSameDropTarget]);
  
  const setGroupDragOverDropTarget = useCallback((path: string | null) => {
      setDragOverDropTarget(path ? { kind: "group", path } : null);
    }, []);
  
  const moveHostToGroup = useCallback((hostId: string, groupPath: string | null) => {
      const targetGroup = groupPath || "";
      const hostToMove = hosts.find((h) => h.id === hostId);
      if (!hostToMove || (hostToMove.group || "") === targetGroup) {
        setDragOverDropTarget(null);
        return;
      }
  
      // Find the most specific (deepest) managed source that matches the target group
      const targetManagedSource = managedSources
        .filter(s => targetGroup === s.groupName || targetGroup.startsWith(s.groupName + "/"))
        .sort((a, b) => b.groupName.length - a.groupName.length)[0];
  
      const movedHost = {
        ...hostToMove,
        group: targetGroup,
      };
      const updatedHost = (() => {
          const h = movedHost;
  
          // Only SSH hosts can be managed (SSH config only supports SSH)
          const canBeManaged = !h.protocol || h.protocol === "ssh";
  
          // Sanitize label if moving to a managed group (SSH config requires no spaces in Host alias)
          let label = h.label;
          if (targetManagedSource && canBeManaged && label) {
            label = label.replace(/\s/g, '');
          }
  
          return {
            ...h,
            label,
            group: targetGroup,
            managedSourceId: (targetManagedSource && canBeManaged) ? targetManagedSource.id : undefined,
          };
        })();
      onUpdateHosts(hosts.map((host) => (host.id === hostId ? updatedHost : host)));
      setDragOverDropTarget(null);
      pulseDropTarget(groupPath ? { kind: "group", path: groupPath } : { kind: "root" });
      toast.success(
        t("vault.hosts.moveToGroup.success", {
          host: hostToMove.label,
          group: groupPath || t("vault.hosts.allHosts"),
        }),
      );
    }, [hosts, managedSources, onUpdateHosts, pulseDropTarget, t]);
  
  const getDropTargetClasses = (target: DropTarget) =>
      cn(
        isSameDropTarget(dragOverDropTarget, target) &&
          "!bg-[#e7ebf0] dark:!bg-white/[0.10]",
        isSameDropTarget(confirmedDropTarget, target) &&
          "!bg-[#dde3ea] dark:!bg-white/[0.14]",
      );
  
  const handleUnmanageGroup = useCallback((groupPath: string) => {
      const source = managedSources.find(s => s.groupName === groupPath);
      if (!source) return;
  
      // Clear managedSourceId from hosts first
      const updatedHosts = hosts.map(h =>
        h.managedSourceId === source.id
          ? { ...h, managedSourceId: undefined }
          : h
      );
      onUpdateHosts(updatedHosts);
  
      // Remove the source association without modifying the SSH config file
      // This preserves the user's file contents while stopping sync
      if (onUnmanageSource) {
        onUnmanageSource(source.id);
      } else {
        // Fallback if onUnmanageSource not available
        const updatedSources = managedSources.filter(s => s.id !== source.id);
        onUpdateManagedSources(updatedSources);
      }
  
      toast.success(t("vault.managedSource.unmanageSuccess"));
    }, [managedSources, hosts, onUpdateHosts, onUpdateManagedSources, onUnmanageSource, t]);

  return {
    getDropTargetClasses,
    handleUnmanageGroup,
    managedGroupPaths,
    moveHostToGroup,
    setDragOverDropTarget,
    setGroupDragOverDropTarget,
  };
}
