/**
 * ItemRow — a single list item row with checkbox, text, drag handle, and delete.
 *
 * Design contract (UI-SPEC §ItemRow):
 *   - 44px min-height touch target
 *   - Checkbox: 20px visual / 44px touch target, --color-member-0 fill when checked
 *   - Item text: plain-text JSX (T-04-06 XSS guard); line-through + muted when completed
 *   - GripVertical handle on active items — useSortable listeners scoped to handle only
 *     (Plan 05: dnd-kit wired; touch requires 200ms long-press via TouchSensor in ListDetail)
 *   - Delete affordance: hover Trash2 on desktop / swipe-left zone on phone
 *   - No confirmation on delete (D-06)
 *   - CSS.Transform.toString(transform) + transition for drag animation (D-14 remote reorder)
 *
 * Sortable behavior:
 *   - useSortable({ id: item.id }) — must be wrapped by SortableContext in the parent
 *   - listeners attached to handle button ONLY — taps on checkbox/text/delete still work
 *   - isDragging: opacity 0.8 + scale-down to give visual drag feedback
 *   - Completed items receive no handle (not reorderable per UI-SPEC)
 *
 * Optimistic behavior (caller responsibility):
 *   - Checking: caller's mutation moves item to completed section immediately
 *   - Delete: caller removes item from cache; no rollback (D-09)
 */

import { useState } from 'react';
import { GripVertical, Trash2 } from 'lucide-react';
import { useSortable } from '@dnd-kit/sortable';
import type { ListItem } from '../api/listsClient.js';

/**
 * Convert a dnd-kit Transform object to a CSS transform string.
 * Equivalent to CSS.Transform.toString() from @dnd-kit/utilities (not a direct
 * dependency; inline to avoid adding @dnd-kit/utilities as a separate dep).
 */
function transformToString(
  transform: { x: number; y: number; scaleX: number; scaleY: number } | null,
): string | undefined {
  if (!transform) return undefined;
  const { x, y } = transform;
  return `translate3d(${x ? Math.round(x) : 0}px, ${y ? Math.round(y) : 0}px, 0)`;
}

interface ItemRowProps {
  item: ListItem;
  /** Whether this is an active (unchecked) item — shows drag handle */
  isActive: boolean;
  onCheck: (itemId: number, checked: boolean) => void;
  onDelete: (itemId: number) => void;
  /** Opacity for optimistic pending state (e.g. 0.6 while add is confirming) */
  optimisticOpacity?: number;
}

export function ItemRow({
  item,
  isActive,
  onCheck,
  onDelete,
  optimisticOpacity = 1,
}: ItemRowProps) {
  const [hovered, setHovered] = useState(false);
  const [swipeRevealed, setSwipeRevealed] = useState(false);
  const [touchStartX, setTouchStartX] = useState<number | null>(null);

  // useSortable is always called (React hook rules), but listeners are only
  // attached to the handle button when isActive=true.
  const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
    id: item.id,
  });

  function handleCheckboxClick() {
    onCheck(item.id, !item.checked);
  }

  function handleDelete() {
    setSwipeRevealed(false);
    onDelete(item.id);
  }

  function handleTouchStart(e: React.TouchEvent) {
    setTouchStartX(e.touches[0].clientX);
  }

  function handleTouchEnd(e: React.TouchEvent) {
    if (touchStartX === null) return;
    const deltaX = touchStartX - e.changedTouches[0].clientX;
    if (deltaX > 60) {
      // Swipe-left: reveal delete zone
      setSwipeRevealed(true);
    } else if (deltaX < -20) {
      // Swipe-right: hide delete zone
      setSwipeRevealed(false);
    }
    setTouchStartX(null);
  }

  // D-14: transformToString + transition animates remote reorders arriving
  // via SSE (Plan 06). The transition fallback 'transform 150ms ease-out' applies
  // when dnd-kit's own transition is not active (i.e. for non-drag CSS changes).
  const transformStr = transformToString(transform);
  const computedTransition = transition ?? 'transform 150ms ease-out';

  return (
    <div
      ref={setNodeRef}
      style={{
        position: 'relative',
        overflow: 'hidden',
        // D-14: transition slot for remote reorder animation
        transform: transformStr,
        transition: computedTransition,
        opacity: isDragging ? 0.8 * optimisticOpacity : optimisticOpacity,
        // Slight scale-down when dragging to give a "picked up" feel
        ...(isDragging ? { scale: '0.98' } : {}),
      }}
      {...attributes}
      onMouseEnter={() => setHovered(true)}
      onMouseLeave={() => setHovered(false)}
      onTouchStart={handleTouchStart}
      onTouchEnd={handleTouchEnd}
    >
      {/* Main row */}
      <div
        style={{
          display: 'flex',
          alignItems: 'center',
          gap: 'var(--space-2)',
          minHeight: '44px',
          padding: 'var(--space-2) var(--space-4)',
          background: isDragging
            ? 'var(--color-surface-raised, var(--color-surface))'
            : 'var(--color-surface)',
          transform: swipeRevealed ? 'translateX(-80px)' : 'translateX(0)',
          transition: 'transform 200ms ease',
          fontFamily: 'var(--font-family-base)',
        }}
      >
        {/* Drag handle — listeners scoped to this button only (not whole row).
            Only active items are draggable (completed items are not reorderable). */}
        {isActive && (
          <button
            {...listeners}
            aria-label="Drag to reorder"
            style={{
              background: 'none',
              border: 'none',
              cursor: isDragging ? 'grabbing' : 'grab',
              padding: 'var(--space-1)',
              color: 'var(--color-text-muted)',
              display: 'flex',
              alignItems: 'center',
              minWidth: '20px',
              touchAction: 'none', // prevent browser scroll interference during drag
            }}
          >
            <GripVertical size={16} aria-hidden="true" />
          </button>
        )}

        {/* Checkbox (44px touch area, 20px visual) */}
        <button
          role="checkbox"
          aria-checked={item.checked}
          aria-label={item.text}
          onClick={handleCheckboxClick}
          style={{
            width: '44px',
            height: '44px',
            minWidth: '44px',
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            background: 'none',
            border: 'none',
            cursor: 'pointer',
            padding: 0,
          }}
        >
          <div
            style={{
              width: '20px',
              height: '20px',
              borderRadius: '4px',
              border: item.checked ? 'none' : '2px solid var(--color-border)',
              background: item.checked ? 'var(--color-member-0)' : 'transparent',
              display: 'flex',
              alignItems: 'center',
              justifyContent: 'center',
              flexShrink: 0,
            }}
          >
            {item.checked && (
              <svg width="12" height="9" viewBox="0 0 12 9" fill="none" aria-hidden="true">
                <path
                  d="M1 4L4.5 7.5L11 1"
                  stroke="white"
                  strokeWidth="2"
                  strokeLinecap="round"
                  strokeLinejoin="round"
                />
              </svg>
            )}
          </div>
        </button>

        {/* Item text — plain text only (T-04-06 XSS guard: no dangerouslySetInnerHTML) */}
        <span
          style={{
            flex: 1,
            fontSize: 'var(--text-body-size, 15px)',
            fontWeight: 400,
            color: item.checked ? 'var(--color-text-muted)' : 'var(--color-text-primary)',
            textDecoration: item.checked ? 'line-through' : 'none',
            wordBreak: 'break-word',
          }}
        >
          {item.text}
        </span>

        {/* Desktop delete button — visible on hover */}
        {hovered && (
          <button
            onClick={handleDelete}
            aria-label={`Delete ${item.text}`}
            style={{
              background: 'none',
              border: 'none',
              cursor: 'pointer',
              padding: 'var(--space-2)',
              color: 'var(--color-destructive)',
              display: 'flex',
              alignItems: 'center',
            }}
          >
            <Trash2 size={16} aria-hidden="true" />
          </button>
        )}
      </div>

      {/* Swipe-left delete zone (phone) */}
      {swipeRevealed && (
        <button
          onClick={handleDelete}
          aria-label={`Delete ${item.text}`}
          style={{
            position: 'absolute',
            right: 0,
            top: 0,
            bottom: 0,
            width: '80px',
            background: 'var(--color-destructive)',
            color: '#fff',
            border: 'none',
            cursor: 'pointer',
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            fontSize: 'var(--text-label-size, 13px)',
            fontWeight: 600,
          }}
        >
          Delete
        </button>
      )}
    </div>
  );
}
