/**
 * ObjectPanel — right-side layer list for canvas objects.
 *
 * Shows objects ordered by z-index (top of list = frontmost).
 * Supports: row select, shift-click multi-select, double-click rename,
 * visibility toggle, lock toggle, and drag-to-reorder.
 */

import { useCallback, useRef, useState } from 'react';
import type { CanvasObject } from '../../types/canvas';

// -- Icons (simple text-based) -----------------------------------------------

const TYPE_ICONS: Record<CanvasObject['type'], string> = {
  rect: '▭',
  circle: '○',
  ellipse: '⬯',
  line: '╱',
  image: '🖼',
  text: 'T',
};

// -- Props --------------------------------------------------------------------

export interface ObjectPanelProps {
  objects: CanvasObject[];
  selectedIds: string[];
  onSelect: (ids: string[], additive: boolean) => void;
  onReorder: (id: string, toIndex: number) => void;
  onToggleVisibility: (id: string) => void;
  onToggleLock: (id: string) => void;
  onRename: (id: string, newName: string) => void;
}

// -- Component ----------------------------------------------------------------

export default function ObjectPanel({
  objects,
  selectedIds,
  onSelect,
  onReorder,
  onToggleVisibility,
  onToggleLock,
  onRename,
}: ObjectPanelProps) {
  const [editingId, setEditingId] = useState<string | null>(null);
  const [editValue, setEditValue] = useState('');
  const inputRef = useRef<HTMLInputElement | null>(null);
  const dragItemRef = useRef<string | null>(null);
  const dragOverRef = useRef<number | null>(null);

  // Show list in reverse z-order so frontmost layer is at top
  const displayObjects = [...objects].reverse();

  // -- Row click → select ---------------------------------------------------

  const handleRowClick = useCallback(
    (id: string, e: React.MouseEvent) => {
      onSelect([id], e.shiftKey);
    },
    [onSelect],
  );

  // -- Double-click → rename ------------------------------------------------

  const handleDoubleClick = useCallback((id: string, currentName: string) => {
    setEditingId(id);
    setEditValue(currentName);
    // Focus input on next tick
    setTimeout(() => inputRef.current?.select(), 0);
  }, []);

  const handleRenameSubmit = useCallback(
    (id: string) => {
      const trimmed = editValue.trim();
      if (trimmed) {
        onRename(id, trimmed);
      }
      setEditingId(null);
    },
    [editValue, onRename],
  );

  // -- Drag to reorder ------------------------------------------------------

  const handleDragStart = useCallback((id: string) => {
    dragItemRef.current = id;
  }, []);

  const handleDragOver = useCallback(
    (e: React.DragEvent, displayIndex: number) => {
      e.preventDefault();
      dragOverRef.current = displayIndex;
    },
    [],
  );

  const handleDrop = useCallback(
    (_e: React.DragEvent) => {
      const dragId = dragItemRef.current;
      const overDisplayIdx = dragOverRef.current;
      if (dragId == null || overDisplayIdx == null) return;

      // Convert display index (reversed) back to objects array index
      const toIndex = objects.length - 1 - overDisplayIdx;
      onReorder(dragId, toIndex);

      dragItemRef.current = null;
      dragOverRef.current = null;
    },
    [objects.length, onReorder],
  );

  return (
    <div className="object-panel" data-testid="object-panel">
      <div className="object-panel-header">Layers</div>
      {displayObjects.length === 0 ? (
        <div className="object-panel-empty">No objects on canvas</div>
      ) : (
        <div className="object-panel-list" role="listbox" aria-label="Layer list">
          {displayObjects.map((obj, displayIdx) => {
            const isSelected = selectedIds.includes(obj.id);
            const isEditing = editingId === obj.id;

            return (
              <div
                key={obj.id}
                role="option"
                aria-selected={isSelected}
                className={`object-panel-row${isSelected ? ' object-panel-row--selected' : ''}${!obj.visible ? ' object-panel-row--hidden' : ''}`}
                onClick={(e) => handleRowClick(obj.id, e)}
                onDoubleClick={() => handleDoubleClick(obj.id, obj.name)}
                draggable={!isEditing}
                onDragStart={() => handleDragStart(obj.id)}
                onDragOver={(e) => handleDragOver(e, displayIdx)}
                onDrop={handleDrop}
                data-testid={`object-row-${obj.id}`}
              >
                {/* Drag handle */}
                <span className="object-panel-drag" aria-hidden="true">⠿</span>

                {/* Type icon */}
                <span className="object-panel-type-icon" title={obj.type}>
                  {TYPE_ICONS[obj.type]}
                </span>

                {/* Name (or edit input) */}
                {isEditing ? (
                  <input
                    ref={inputRef}
                    className="object-panel-name-input"
                    value={editValue}
                    onChange={(e) => setEditValue(e.target.value)}
                    onBlur={() => handleRenameSubmit(obj.id)}
                    onKeyDown={(e) => {
                      if (e.key === 'Enter') handleRenameSubmit(obj.id);
                      if (e.key === 'Escape') setEditingId(null);
                    }}
                    onClick={(e) => e.stopPropagation()}
                    data-testid={`rename-input-${obj.id}`}
                  />
                ) : (
                  <span className="object-panel-name" title={obj.name}>
                    {obj.name}
                  </span>
                )}

                {/* Visibility toggle */}
                <button
                  type="button"
                  className={`object-panel-icon-btn${obj.visible ? '' : ' object-panel-icon-btn--off'}`}
                  onClick={(e) => {
                    e.stopPropagation();
                    onToggleVisibility(obj.id);
                  }}
                  title={obj.visible ? 'Hide' : 'Show'}
                  aria-label={obj.visible ? 'Hide layer' : 'Show layer'}
                  data-testid={`visibility-toggle-${obj.id}`}
                >
                  {obj.visible ? '👁' : '👁‍🗨'}
                </button>

                {/* Lock toggle */}
                <button
                  type="button"
                  className={`object-panel-icon-btn${obj.locked ? ' object-panel-icon-btn--on' : ''}`}
                  onClick={(e) => {
                    e.stopPropagation();
                    onToggleLock(obj.id);
                  }}
                  title={obj.locked ? 'Unlock' : 'Lock'}
                  aria-label={obj.locked ? 'Unlock layer' : 'Lock layer'}
                  data-testid={`lock-toggle-${obj.id}`}
                >
                  {obj.locked ? '🔒' : '🔓'}
                </button>
              </div>
            );
          })}
        </div>
      )}
    </div>
  );
}
