# Canvas Component Architecture

This document describes the refactored Canvas component architecture, which follows clean architecture principles and implements the Command Pattern for undo/redo functionality.

## Overview

The Canvas component has been refactored to:
1. **Separate node types into individual files** for better maintainability
2. **Extract common logic into reusable hooks** to reduce duplication
3. **Implement the Command Pattern** for robust undo/redo functionality
4. **Add debounced auto-save** to prevent data loss

## Directory Structure

```
canvas/
├── commands/              # Command Pattern implementation
│   ├── Command.ts        # Command interface
│   ├── CommandManager.ts # Command history manager
│   ├── AddNodeCommand.ts
│   ├── DeleteNodeCommand.ts
│   ├── UpdateNodeCommand.ts
│   ├── MoveNodeCommand.ts
│   ├── AddEdgeCommand.ts
│   ├── DeleteEdgeCommand.ts
│   └── index.ts
├── hooks/                 # Custom hooks
│   ├── useAutoSave.ts           # Generic auto-save hook
│   ├── useCanvasAutoSave.ts     # Canvas-specific auto-save
│   ├── useCanvasState.ts        # Canvas state management
│   ├── useCanvasNavigation.ts   # Canvas navigation (next/prev)
│   ├── useCanvasContextMenu.ts  # Context menu logic
│   ├── useUndoRedo.ts           # Command-based undo/redo
│   └── ... (existing hooks)
├── nodes/
│   ├── types/            # Individual node type components
│   │   ├── PromptInputNode.tsx
│   │   ├── ImageGeneratorNode.tsx
│   │   ├── VideoGeneratorNode.tsx
│   │   ├── AudioGeneratorNode.tsx
│   │   ├── VideoAnalyzerNode.tsx
│   │   ├── ImageEditorNode.tsx
│   │   ├── InfoDisplayNode.tsx
│   │   ├── PromptGeneratorNode.tsx
│   │   └── index.ts
│   ├── BaseNode.tsx      # Base node component with common logic
│   └── AppNode.tsx       # Original unified node (still supported)
└── Canvas.tsx            # Main Canvas component
```

## Key Components

### 1. Node Type Separation

Each node type now has its own component file, making it easier to:
- Understand and modify individual node types
- Add new node types without affecting existing ones
- Test node types in isolation

**Example:**
```tsx
// PromptInputNode.tsx
export const PromptInputNode = memo(({ id, data, selected, dragging }) => {
    return (
        <BaseNode
            id={id}
            data={data}
            selected={selected}
            dragging={dragging}
            icon={Type}
            color="text-amber-400"
            renderer={PromptInputRenderer}
        />
    );
});
```

### 2. BaseNode Component

The `BaseNode` component extracts common logic shared by all node types:
- Auto-execute logic
- Node dimensions
- Data synchronization
- Node actions (download, expand, crop, etc.)
- Hover and resize state management

This reduces code duplication and ensures consistent behavior across all node types.

### 3. Command Pattern for Undo/Redo

The Command Pattern provides a robust and extensible undo/redo system:

**Command Interface:**
```typescript
interface Command {
    execute(): void;
    undo(): void;
    getDescription?(): string;
}
```

**Available Commands:**
- `AddNodeCommand` - Add a node to the canvas
- `DeleteNodeCommand` - Delete a node and its connections
- `UpdateNodeCommand` - Update node data
- `MoveNodeCommand` - Move a node to a new position
- `AddEdgeCommand` - Add an edge between nodes
- `DeleteEdgeCommand` - Delete an edge

**Usage:**
```typescript
const { execute, undo, redo, canUndo, canRedo } = useUndoRedo();

// Execute a command
const command = new AddNodeCommand(newNode, setNodes);
execute(command);

// Undo/Redo
if (canUndo) undo();
if (canRedo) redo();
```

**Benefits:**
- **Extensible**: Easy to add new command types
- **Testable**: Commands can be tested in isolation
- **Reliable**: Guaranteed state consistency
- **Debuggable**: Each command has a description

### 4. Auto-Save with Debouncing

The auto-save system prevents data loss while minimizing server requests:

**Generic Auto-Save Hook:**
```typescript
const { triggerSave, cancelSave } = useAutoSave(
    data,
    async (data) => {
        await apiClient.put(`/canvas/${canvasId}`, data);
    },
    { delay: 2000 }
);
```

**Canvas-Specific Auto-Save:**
```typescript
const { triggerSave } = useCanvasAutoSave(nodes, edges, {
    canvasId: 'canvas-123',
    canvasType: 'asset',
    isLoaded: true,
    delay: 2000,
    onSaveComplete: () => console.log('Saved!'),
    onSaveError: (error) => console.error('Save failed:', error)
});
```

**Features:**
- **Debounced**: Waits 2 seconds after last change before saving
- **Smart**: Only saves if data has actually changed
- **Safe**: Prevents concurrent saves
- **Flexible**: Can trigger immediate save or cancel pending save

### 5. Extracted Hooks

Common Canvas logic has been extracted into reusable hooks:

**useCanvasState:**
- Manages Canvas store state (nodes, edges, history)
- Provides project data (assets, storyboards, episodes)
- Memoizes sorted storyboards for consistent navigation

**useCanvasNavigation:**
- Handles next/prev canvas navigation
- Supports both asset and storyboard navigation
- Maintains context (same type assets, sorted storyboards)

**useCanvasContextMenu:**
- Manages context menu state and actions
- Handles node/edge/pane context menus
- Provides file replacement functionality

## Migration Guide

### Using New Node Types

To use the new separated node types, update your node type registry:

```typescript
import {
    PromptInputNode,
    ImageGeneratorNode,
    VideoGeneratorNode,
    // ... other node types
} from './nodes/types';

const nodeTypes: NodeTypes = {
    promptInput: PromptInputNode,
    imageGenerator: ImageGeneratorNode,
    videoGenerator: VideoGeneratorNode,
    // ... other node types
};
```

### Using Command-Based Undo/Redo

Replace the old history-based undo/redo with the command pattern:

**Old:**
```typescript
const { takeSnapshot, undo, redo } = useHistory(setNodes, setEdges);
takeSnapshot(nodes, edges);
undo(nodes, edges);
```

**New:**
```typescript
const { execute, undo, redo } = useUndoRedo();

// When adding a node
const command = new AddNodeCommand(newNode, setNodes);
execute(command);

// Undo/Redo
undo(); // No need to pass current state
redo();
```

### Using Auto-Save

Add auto-save to your Canvas:

```typescript
const { triggerSave } = useCanvasAutoSave(nodes, edges, {
    canvasId: activeCanvasId,
    canvasType: activeCanvasType,
    isLoaded: isCanvasLoaded,
    onSaveStatusChange: (isSaving) => {
        // Update UI to show save status
    }
});

// Manual save
<button onClick={triggerSave}>Save Now</button>
```

## Testing

### Testing Commands

Commands can be tested in isolation:

```typescript
describe('AddNodeCommand', () => {
    it('should add node on execute', () => {
        const nodes: AppNodeType[] = [];
        const setNodes = jest.fn((updater) => {
            nodes.push(...updater(nodes));
        });
        
        const command = new AddNodeCommand(mockNode, setNodes);
        command.execute();
        
        expect(nodes).toContain(mockNode);
    });
    
    it('should remove node on undo', () => {
        // ... test undo
    });
});
```

### Testing Auto-Save

Test the debounce behavior:

```typescript
describe('useAutoSave', () => {
    it('should debounce saves', async () => {
        const saveFn = jest.fn();
        const { rerender } = renderHook(
            ({ data }) => useAutoSave(data, saveFn, { delay: 100 }),
            { initialProps: { data: { value: 1 } } }
        );
        
        // Change data multiple times
        rerender({ data: { value: 2 } });
        rerender({ data: { value: 3 } });
        
        // Should only save once after delay
        await waitFor(() => expect(saveFn).toHaveBeenCalledTimes(1));
        expect(saveFn).toHaveBeenCalledWith({ value: 3 });
    });
});
```

## Best Practices

1. **Use Commands for State Changes**: Always use commands for operations that should be undoable
2. **Keep Node Types Focused**: Each node type should handle only its specific rendering logic
3. **Extract Common Logic**: If multiple node types share logic, extract it to BaseNode or a hook
4. **Test Commands**: Write tests for each command to ensure correct execute/undo behavior
5. **Monitor Auto-Save**: Provide visual feedback when auto-save is in progress
6. **Handle Save Errors**: Always handle and display save errors to the user

## Future Improvements

1. **Batch Commands**: Implement composite commands for operations that involve multiple changes
2. **Command Compression**: Merge similar consecutive commands (e.g., multiple move commands)
3. **Persistent Undo History**: Save undo history to allow undo across sessions
4. **Optimistic Updates**: Update UI immediately while save is in progress
5. **Conflict Resolution**: Handle conflicts when multiple users edit the same canvas

## Related Documentation

- [React Flow Documentation](https://reactflow.dev/)
- [Command Pattern](https://refactoring.guru/design-patterns/command)
- [Debouncing in React](https://www.freecodecamp.org/news/debouncing-explained/)
