import { useState, useCallback, useRef } from 'react';
import { useDraggable } from '@dnd-kit/core';
import { Trash2, GripVertical, GripHorizontal } from 'lucide-react';
import { toast } from 'sonner';
import type { Module } from '../../types';
import { cn } from '../../lib/utils';
import { MODULE_TYPE_COLORS, MODULE_TYPE_LABELS, U_HEIGHT_PX } from '../../lib/constants';
import { Badge } from '../ui/Badge';
import { ConfirmDialog } from '../ui/ConfirmDialog';
import { ModuleEditPanel } from '../modals/ModuleEditPanel';
import { PortConfigModal } from '../modals/PortConfigModal';
import { useRackStore } from '../../store/useRackStore';
import { apiClient } from '../../api/client';

interface ModuleBlockProps {
  module: Module;
}

export function ModuleBlock({ module }: ModuleBlockProps) {
  const { racks, removeModuleLocal, updateModuleLocal } = useRackStore();
  const [hovered, setHovered] = useState(false);
  const [editOpen, setEditOpen] = useState(false);
  const [confirmDeleteOpen, setConfirmDeleteOpen] = useState(false);
  const [deletingLoading, setDeletingLoading] = useState(false);
  const [portModalOpen, setPortModalOpen] = useState(false);
  const [selectedPortId, setSelectedPortId] = useState<string | null>(null);

  // Resize state
  const [previewUSize, setPreviewUSize] = useState<number | null>(null);
  const isResizing = useRef(false);
  const resizeStartY = useRef(0);
  const resizeStartUSize = useRef(0);

  const { attributes, listeners, setNodeRef, isDragging } = useDraggable({
    id: `module-${module.id}`,
    disabled: isResizing.current,
    data: {
      dragType: 'module',
      moduleId: module.id,
      fromRackId: module.rackId,
      fromUPosition: module.uPosition,
      uSize: module.uSize,
      label: module.name,
    },
  });

  const colors = MODULE_TYPE_COLORS[module.type];
  const displayUSize = previewUSize ?? module.uSize;
  const height = displayUSize * U_HEIGHT_PX;
  const hasPorts = module.ports.length > 0;

  // Compute the maximum allowed uSize for this module (rack bounds + collision)
  const maxResizeU = useCallback((): number => {
    const rack = racks.find((r) => r.id === module.rackId);
    if (!rack) return module.uSize;
    // Bound by rack totalU
    const rackMax = rack.totalU - module.uPosition + 1;
    // Find the first module that starts at uPosition >= module.uPosition + 1 (anything below us)
    const nextStart = rack.modules
      .filter((m) => m.id !== module.id && m.uPosition > module.uPosition)
      .reduce((min, m) => Math.min(min, m.uPosition), rack.totalU + 1);
    const collisionMax = nextStart - module.uPosition;
    return Math.min(rackMax, collisionMax);
  }, [racks, module]);

  function handleResizePointerDown(e: React.PointerEvent<HTMLDivElement>) {
    e.preventDefault();
    e.stopPropagation();
    isResizing.current = true;
    resizeStartY.current = e.clientY;
    resizeStartUSize.current = module.uSize;
    (e.currentTarget as HTMLDivElement).setPointerCapture(e.pointerId);
  }

  function handleResizePointerMove(e: React.PointerEvent<HTMLDivElement>) {
    if (!isResizing.current) return;
    const deltaY = e.clientY - resizeStartY.current;
    const deltaU = Math.round(deltaY / U_HEIGHT_PX);
    const max = maxResizeU();
    const newU = Math.max(1, Math.min(resizeStartUSize.current + deltaU, max));
    setPreviewUSize(newU);
  }

  async function handleResizePointerUp(e: React.PointerEvent<HTMLDivElement>) {
    if (!isResizing.current) return;
    isResizing.current = false;
    (e.currentTarget as HTMLDivElement).releasePointerCapture(e.pointerId);
    const finalU = previewUSize ?? module.uSize;
    setPreviewUSize(null);
    if (finalU === module.uSize) return;
    try {
      await apiClient.modules.update(module.id, { uSize: finalU });
      updateModuleLocal(module.id, { uSize: finalU });
    } catch (err) {
      toast.error(err instanceof Error ? err.message : 'Resize failed');
    }
  }

  async function handleDelete() {
    setDeletingLoading(true);
    try {
      await apiClient.modules.delete(module.id);
      removeModuleLocal(module.id);
      toast.success(`${module.name} removed`);
    } catch (e) {
      toast.error(e instanceof Error ? e.message : 'Delete failed');
    } finally {
      setDeletingLoading(false);
      setConfirmDeleteOpen(false);
    }
  }

  function openPort(portId: string) {
    setSelectedPortId(portId);
    setPortModalOpen(true);
  }

  return (
    <>
      <div
        ref={setNodeRef}
        className={cn(
          'relative w-full border-l-2 select-none flex flex-col justify-between px-2 py-0.5 overflow-hidden transition-opacity',
          colors.bg,
          colors.border,
          isDragging ? 'opacity-0' : 'cursor-pointer',
          !isDragging && hovered && 'brightness-110',
          previewUSize !== null && 'ring-1 ring-white/30'
        )}
        style={{ height }}
        onMouseEnter={() => setHovered(true)}
        onMouseLeave={() => setHovered(false)}
        onClick={() => !isDragging && !isResizing.current && setEditOpen(true)}
        role="button"
        tabIndex={0}
        aria-label={`Edit ${module.name}`}
        onKeyDown={(e) => e.key === 'Enter' && setEditOpen(true)}
      >
        {/* Drag handle */}
        <div
          {...listeners}
          {...attributes}
          className="absolute left-0 top-0 bottom-6 w-4 flex items-start justify-center pt-1.5 cursor-grab active:cursor-grabbing text-white/30 hover:text-white/70 transition-colors z-10 touch-none"
          onClick={(e) => e.stopPropagation()}
          aria-label={`Drag ${module.name}`}
        >
          <GripVertical size={10} />
        </div>

        {/* Main content */}
        <div className="flex items-center gap-1 min-w-0 pl-3">
          <span className="text-xs font-semibold text-white truncate flex-1">{module.name}</span>
          <Badge variant="slate" className="text-[10px] shrink-0">
            {MODULE_TYPE_LABELS[module.type]}
          </Badge>
        </div>

        {module.ipAddress && (
          <div className="text-[10px] text-slate-300 font-mono truncate">{module.ipAddress}</div>
        )}

        {/* U-size preview label during resize */}
        {previewUSize !== null && (
          <div className="absolute inset-0 flex items-center justify-center pointer-events-none">
            <span className="text-xs font-bold text-white/70 bg-black/30 px-1.5 py-0.5 rounded">
              {previewUSize}U
            </span>
          </div>
        )}

        {/* Port dots — only if module has ports and enough height */}
        {hasPorts && height >= 28 && previewUSize === null && (
          <div
            className="flex flex-wrap gap-0.5 mt-0.5"
            onClick={(e) => e.stopPropagation()}
          >
            {module.ports.slice(0, 32).map((port) => {
              const hasVlan = port.vlans.length > 0;
              return (
                <button
                  key={port.id}
                  onClick={() => openPort(port.id)}
                  aria-label={`Port ${port.portNumber}`}
                  className={cn(
                    'w-2.5 h-2.5 rounded-sm border transition-colors',
                    hasVlan
                      ? 'bg-green-400 border-green-500 hover:bg-green-300'
                      : 'bg-slate-600 border-slate-500 hover:bg-slate-400'
                  )}
                />
              );
            })}
            {module.ports.length > 32 && (
              <span className="text-[9px] text-slate-400">+{module.ports.length - 32}</span>
            )}
          </div>
        )}

        {/* Delete button — hover only */}
        {hovered && previewUSize === null && (
          <button
            className="absolute top-0.5 right-0.5 p-0.5 rounded bg-red-800/80 hover:bg-red-600 text-white transition-colors z-10"
            onClick={(e) => {
              e.stopPropagation();
              setConfirmDeleteOpen(true);
            }}
            aria-label={`Delete ${module.name}`}
          >
            <Trash2 size={11} />
          </button>
        )}

        {/* Resize handle — bottom edge */}
        <div
          className={cn(
            'absolute bottom-0 left-0 right-0 h-3 flex items-center justify-center z-20',
            'cursor-ns-resize touch-none',
            hovered || previewUSize !== null
              ? 'opacity-100'
              : 'opacity-0 hover:opacity-100',
            'transition-opacity'
          )}
          onPointerDown={handleResizePointerDown}
          onPointerMove={handleResizePointerMove}
          onPointerUp={handleResizePointerUp}
          onClick={(e) => e.stopPropagation()}
          aria-label="Resize module"
          title="Drag to resize"
        >
          <GripHorizontal size={10} className="text-white/50 pointer-events-none" />
        </div>
      </div>

      <ModuleEditPanel module={module} open={editOpen} onClose={() => setEditOpen(false)} />

      <ConfirmDialog
        open={confirmDeleteOpen}
        onClose={() => setConfirmDeleteOpen(false)}
        onConfirm={handleDelete}
        title="Remove Module"
        message={`Remove "${module.name}" from the rack? This will also delete all associated port configuration.`}
        confirmLabel="Remove"
        loading={deletingLoading}
      />

      {selectedPortId && (
        <PortConfigModal
          portId={selectedPortId}
          open={portModalOpen}
          onClose={() => {
            setPortModalOpen(false);
            setSelectedPortId(null);
          }}
        />
      )}
    </>
  );
}
