# useCommand Hook - Guia Completo

O `useCommand` é o hook fundamental para executar comandos existentes no Commander com controle total sobre configurações, estado e callbacks.

## 📋 Índice

- [Visão Geral](#visão-geral)
- [Assinaturas e Tipos](#assinaturas-e-tipos)
- [Configurações](#configurações)
- [Exemplos Práticos](#exemplos-práticos)
- [Estado e Tracking](#estado-e-tracking)
- [Tratamento de Erros](#tratamento-de-erros)
- [Performance e Otimizações](#performance-e-otimizações)

## 🎯 Visão Geral

O `useCommand` oferece múltiplas formas de uso, desde execução simples até controle completo com tracking de estado:

```tsx
// 1. Execução simples
const saveFile = useCommand('file:save')
await saveFile({ filename: 'doc.txt' })

// 2. Com configurações
const saveFile = useCommand('file:save', { 
  throwOnError: false,
  timeout: 5000 
})

// 3. Com tracking de estado completo
const saveFile = useCommand('file:save', { 
  trackState: true 
})
console.log(saveFile.isLoading, saveFile.lastResult)

// 4. Objeto completo de controle
const saveFile = useCommand('file:save', { 
  returnInvoker: true 
})
```

## 🔧 Assinaturas e Tipos

### Assinaturas Disponíveis

```tsx
// 1. Básico - retorna função invoke
useCommand<TInput, TOutput>(key: CommandKey): (input?: TInput) => Promise<TOutput>

// 2. Com opções - retorna função configurada
useCommand<TInput, TOutput>(
  key: CommandKey,
  options: UseCommandOptions & { returnInvoker?: false }
): (input?: TInput) => Promise<TOutput>

// 3. Objeto completo - returnInvoker: true
useCommand<TInput, TOutput>(
  key: CommandKey,
  options: UseCommandOptions & { returnInvoker: true }
): CommandInvoker<TInput, TOutput>

// 4. Com tracking - trackState: true
useCommand<TInput, TOutput>(
  key: CommandKey,
  options: UseCommandOptions & { trackState: true }
): CommandInvoker<TInput, TOutput>
```

### Interface CommandInvoker

```tsx
interface CommandInvoker<TInput, TOutput> {
  // Estado do comando
  exists: boolean
  isAvailable: boolean
  isLoading: boolean
  
  // Resultados e histórico
  lastResult: TOutput | null
  lastError: Error | null
  lastInput: TInput | null
  lastExecution: Date | null
  executionCount: number
  
  // Comando completo
  command: Command<TInput, TOutput> | null
  
  // Métodos de execução
  invoke: (input?: TInput) => Promise<TOutput>
  attempt: (input?: TInput) => Promise<ExecutionResult<TOutput>>
  execute: (input?: TInput, callbacks?: ExecuteCallbacks) => Promise<TOutput | null>
  
  // Verificações
  canInvoke: (input?: TInput) => Promise<boolean>
  validateInput: (input?: TInput) => boolean | string
  
  // Utilitários
  reset: () => void
  clearError: () => void
  refresh: () => void
}
```

## ⚙️ Configurações

### UseCommandOptions Interface

```tsx
interface UseCommandOptions<TInput, TOutput> {
  // Execução
  source?: 'palette' | 'shortcut' | 'api'  // Default: 'api'
  throwOnError?: boolean                    // Default: true
  timeout?: number                         // Timeout em ms
  
  // Retry & Debounce
  retry?: number                           // Tentativas (default: 0)
  retryDelay?: number | ((attempt: number) => number)
  debounce?: number                        // Debounce em ms
  throttle?: number                        // Throttle em ms
  
  // Input handling
  defaultInput?: Partial<TInput>           // Input padrão
  validateInput?: (input?: TInput) => boolean | string
  transformInput?: (input?: TInput) => TInput
  
  // Output handling
  transformOutput?: (output: TOutput) => TOutput
  
  // Callbacks
  onSuccess?: (result: TOutput, input?: TInput) => void
  onError?: (error: Error, input?: TInput) => void
  onFinally?: (input?: TInput) => void
  
  // Estado
  trackState?: boolean                     // Ativa tracking
  returnInvoker?: boolean                  // Retorna objeto completo
  resetOnKeyChange?: boolean               // Reset ao mudar key
}
```

## 📚 Exemplos Práticos

### 1. Execução Básica

```tsx
function FileEditor() {
  // Forma mais simples
  const saveFile = useCommand<SaveInput, SaveResult>('file:save')
  
  const handleSave = async () => {
    try {
      const result = await saveFile({ 
        filename: 'document.txt',
        content: editorContent 
      })
      toast.success(`Salvo: ${result.filename}`)
    } catch (error) {
      toast.error('Erro ao salvar')
    }
  }
  
  return <button onClick={handleSave}>Save</button>
}
```

### 2. Com Configurações Avançadas

```tsx
function RobustUploader() {
  const uploadFile = useCommand('file:upload', {
    retry: 3,                              // 3 tentativas
    retryDelay: (attempt) => attempt * 1000, // Delay progressivo
    timeout: 30000,                        // 30s timeout
    throwOnError: false,                   // Não lança erro
    
    defaultInput: { 
      quality: 'high',
      compress: true 
    },
    
    validateInput: (input) => {
      if (!input?.file) return 'Arquivo obrigatório'
      if (input.file.size > 10_000_000) return 'Arquivo muito grande'
      return true
    },
    
    transformInput: (input) => ({
      ...input,
      uploadedAt: new Date(),
      userId: getCurrentUser().id
    }),
    
    onSuccess: (result, input) => {
      analytics.track('file_uploaded', { 
        size: input?.file.size,
        duration: result.duration 
      })
    },
    
    onError: (error, input) => {
      logger.error('Upload failed', { error, filename: input?.file.name })
    }
  })
  
  const handleUpload = async (file: File) => {
    const result = await uploadFile({ file })
    if (result) {
      setUploadedFiles(prev => [...prev, result])
    }
  }
}
```

### 3. Com Tracking de Estado

```tsx
function SmartFileUploader() {
  const uploader = useCommand('file:upload', {
    trackState: true,
    debounce: 500,  // Evita uploads múltiplos
    
    onSuccess: (result) => {
      toast.success(`Upload concluído: ${result.filename}`)
    }
  })
  
  return (
    <div>
      <input 
        type="file" 
        onChange={(e) => uploader.invoke({ file: e.target.files[0] })}
        disabled={uploader.isLoading || !uploader.isAvailable}
      />
      
      {/* Estado visual */}
      {uploader.isLoading && (
        <div className="flex items-center gap-2">
          <Spinner />
          <span>Enviando arquivo...</span>
        </div>
      )}
      
      {/* Histórico */}
      {uploader.lastResult && (
        <div className="text-green-600">
          ✅ Último upload: {uploader.lastResult.filename}
          <br />
          📊 Total de uploads: {uploader.executionCount}
        </div>
      )}
      
      {/* Erro */}
      {uploader.lastError && (
        <div className="text-red-600">
          ❌ Erro: {uploader.lastError.message}
          <button onClick={uploader.clearError}>Limpar</button>
        </div>
      )}
      
      {/* Controles */}
      <div className="flex gap-2 mt-4">
        <button 
          onClick={() => uploader.reset()}
          disabled={uploader.isLoading}
        >
          Reset Estado
        </button>
        
        <button onClick={uploader.refresh}>
          Verificar Disponibilidade
        </button>
      </div>
    </div>
  )
}
```

### 4. Validação e Transformação

```tsx
function UserProfileEditor() {
  const updateProfile = useCommand('user:update', {
    // Validação personalizada
    validateInput: (input) => {
      const errors = []
      if (!input?.email?.includes('@')) errors.push('Email inválido')
      if (!input?.name?.trim()) errors.push('Nome obrigatório')
      return errors.length > 0 ? errors.join(', ') : true
    },
    
    // Transformação de input
    transformInput: (input) => ({
      ...input,
      email: input.email?.toLowerCase(),
      name: input.name?.trim(),
      updatedAt: new Date().toISOString()
    }),
    
    // Transformação de output
    transformOutput: (result) => ({
      ...result,
      avatarUrl: result.avatar ? `/avatars/${result.avatar}` : null
    }),
    
    trackState: true
  })
  
  const handleSubmit = async (formData) => {
    // A validação ocorre automaticamente
    const result = await updateProfile.invoke(formData)
    if (result) {
      // Output já foi transformado
      setUser(result)
    }
  }
}
```

### 5. Execução com Callbacks Inline

```tsx
function DocumentProcessor() {
  const processDoc = useCommand('document:process', {
    returnInvoker: true,
    timeout: 60000  // 1 minuto para processamento
  })
  
  const handleProcess = async (document) => {
    // Usando execute com callbacks inline
    const result = await processDoc.execute(
      { documentId: document.id },
      {
        onSuccess: (result) => {
          notification.success({
            title: 'Processamento Concluído',
            message: `Documento processado em ${result.duration}ms`
          })
        },
        
        onError: (error) => {
          notification.error({
            title: 'Erro no Processamento',
            message: error.message,
            action: {
              label: 'Tentar Novamente',
              onClick: () => handleProcess(document)
            }
          })
        },
        
        onFinally: () => {
          analytics.track('document_process_attempt', {
            documentId: document.id
          })
        }
      }
    )
  }
  
  // Ou usando attempt para execução segura
  const handleSafeProcess = async (document) => {
    const result = await processDoc.attempt({ documentId: document.id })
    
    if (result.success) {
      console.log('Sucesso:', result.result)
    } else {
      console.error('Erro:', result.error)
    }
  }
}
```

## 📊 Estado e Tracking

### Estados Disponíveis

```tsx
const command = useCommand('my:command', { trackState: true })

// Estados booleanos
command.exists          // Comando existe no Commander
command.isAvailable     // Comando disponível (when() = true)
command.isLoading       // Execução em andamento

// Resultados e histórico
command.lastResult      // Último resultado bem-sucedido
command.lastError       // Último erro ocorrido
command.lastInput       // Último input utilizado
command.lastExecution   // Data da última execução
command.executionCount  // Número total de execuções

// Comando original
command.command         // Objeto Command completo
```

### Ciclo de Vida dos Estados

```tsx
// Estado inicial
isLoading: false
lastResult: null
lastError: null
executionCount: 0

// Durante execução
invoke() → isLoading: true

// Sucesso
→ isLoading: false
→ lastResult: [resultado]
→ lastError: null
→ executionCount: +1
→ lastExecution: new Date()

// Erro
→ isLoading: false
→ lastResult: [mantém anterior]
→ lastError: [erro]
→ executionCount: +1
→ lastExecution: new Date()
```

### Reset e Limpeza

```tsx
// Reset completo
command.reset()  // Limpa tudo, volta ao estado inicial

// Limpeza seletiva
command.clearError()  // Remove apenas lastError

// Refresh
command.refresh()  // Re-verifica isAvailable
```

## 🚨 Tratamento de Erros

### Estratégias de Erro

```tsx
// 1. Throw (padrão)
const command = useCommand('risky:operation')
try {
  await command()
} catch (error) {
  // Trata erro
}

// 2. Return null
const command = useCommand('risky:operation', { 
  throwOnError: false 
})
const result = await command()  // null se erro

// 3. ExecutionResult
const command = useCommand('risky:operation', { 
  returnInvoker: true 
})
const result = await command.attempt()
if (result.success) {
  // result.result
} else {
  // result.error
}
```

### Retry Automático

```tsx
const command = useCommand('unreliable:api', {
  retry: 3,
  retryDelay: (attempt) => {
    // Exponential backoff
    return Math.min(1000 * Math.pow(2, attempt), 10000)
  },
  
  onError: (error, input) => {
    console.log(`Tentativa falhou: ${error.message}`)
  }
})
```

## ⚡ Performance e Otimizações

### Debounce e Throttle

```tsx
// Debounce - aguarda pausa na entrada
const searchCommand = useCommand('search:execute', {
  debounce: 300,  // Aguarda 300ms sem nova execução
  transformInput: (input) => ({
    ...input,
    timestamp: Date.now()
  })
})

// Throttle - limita frequência
const saveCommand = useCommand('auto:save', {
  throttle: 5000,  // Máximo 1 save a cada 5s
  throwOnError: false
})
```

### Memoização e Re-renders

```tsx
// ✅ Bom - não recria a cada render
const command = useCommand('stable:command', {
  trackState: true
})

// ⚠️ Cuidado - recria options a cada render
const command = useCommand('unstable:command', {
  onSuccess: (result) => {  // Nova função a cada render
    console.log(result)
  }
})

// ✅ Melhor - callback memoizado
const handleSuccess = useCallback((result) => {
  console.log(result)
}, [])

const command = useCommand('stable:command', {
  onSuccess: handleSuccess
})
```

### Reset Inteligente

```tsx
const command = useCommand(dynamicKey, {
  trackState: true,
  resetOnKeyChange: true  // Reset automático quando key muda
})

// Equivale a:
useEffect(() => {
  command.reset()
}, [dynamicKey])
```

## 🔍 Verificações e Validações

### Verificação de Disponibilidade

```tsx
const command = useCommand('conditional:command', {
  returnInvoker: true
})

// Verificação manual
const canExecute = await command.canInvoke({ userId: 123 })
if (canExecute) {
  await command.invoke({ userId: 123 })
}

// Verificação automática (padrão)
// invoke() já verifica disponibilidade automaticamente
```

### Validação Personalizada

```tsx
const command = useCommand('user:create', {
  validateInput: (input) => {
    // Retorna true = válido
    // Retorna string = mensagem de erro
    // Retorna false = erro genérico
    
    if (!input?.email) return 'Email é obrigatório'
    if (!input?.password || input.password.length < 8) {
      return 'Senha deve ter pelo menos 8 caracteres'
    }
    return true
  },
  
  throwOnError: false  // Para capturar erros de validação
})
```

## 📈 Casos de Uso Avançados

### 1. Command Chaining

```tsx
function DocumentWorkflow() {
  const processDoc = useCommand('document:process', { trackState: true })
  const generatePDF = useCommand('pdf:generate', { trackState: true })
  const sendEmail = useCommand('email:send', { trackState: true })
  
  const runWorkflow = async (document) => {
    try {
      // Processamento
      const processed = await processDoc.invoke({ document })
      
      // Geração PDF
      const pdf = await generatePDF.invoke({ 
        content: processed.content 
      })
      
      // Envio por email
      await sendEmail.invoke({
        to: document.author.email,
        attachment: pdf.url
      })
      
      toast.success('Workflow concluído!')
      
    } catch (error) {
      toast.error(`Workflow falhou: ${error.message}`)
    }
  }
  
  const isWorkflowRunning = 
    processDoc.isLoading || 
    generatePDF.isLoading || 
    sendEmail.isLoading
    
  return (
    <div>
      <button 
        onClick={() => runWorkflow(currentDocument)}
        disabled={isWorkflowRunning}
      >
        {isWorkflowRunning ? 'Processando...' : 'Executar Workflow'}
      </button>
      
      {/* Status de cada etapa */}
      <div className="mt-4 space-y-2">
        <WorkflowStep 
          label="Processamento" 
          status={getStepStatus(processDoc)} 
        />
        <WorkflowStep 
          label="Geração PDF" 
          status={getStepStatus(generatePDF)} 
        />
        <WorkflowStep 
          label="Envio Email" 
          status={getStepStatus(sendEmail)} 
        />
      </div>
    </div>
  )
}
```

### 2. Conditional Execution

```tsx
function SmartSaveButton() {
  const autoSave = useCommand('document:auto-save', {
    trackState: true,
    throttle: 10000,  // Auto-save máximo a cada 10s
    throwOnError: false
  })
  
  const manualSave = useCommand('document:save', {
    trackState: true,
    onSuccess: () => toast.success('Documento salvo!')
  })
  
  // Auto-save quando conteúdo muda
  useEffect(() => {
    if (documentContent && hasUnsavedChanges) {
      autoSave.invoke({ content: documentContent })
    }
  }, [documentContent])
  
  // Save manual
  const handleManualSave = async () => {
    const result = await manualSave.invoke({ 
      content: documentContent,
      force: true  // Força save mesmo se auto-save recente
    })
  }
  
  const lastSaveTime = Math.max(
    autoSave.lastExecution?.getTime() || 0,
    manualSave.lastExecution?.getTime() || 0
  )
  
  return (
    <div>
      <button 
        onClick={handleManualSave}
        disabled={manualSave.isLoading}
      >
        {manualSave.isLoading ? 'Salvando...' : 'Salvar'}
      </button>
      
      <div className="text-sm text-gray-500">
        {lastSaveTime && (
          <span>Último save: {formatDistanceToNow(lastSaveTime)}</span>
        )}
        {autoSave.isLoading && (
          <span className="ml-2">• Auto-save em andamento</span>
        )}
      </div>
    </div>
  )
}
```

## 🎯 Boas Práticas

### 1. Tipagem Consistente

```tsx
// ✅ Defina interfaces claras
interface SaveDocumentInput {
  content: string
  title: string
  tags?: string[]
}

interface SaveDocumentOutput {
  id: string
  url: string
  savedAt: Date
}

const saveDoc = useCommand<SaveDocumentInput, SaveDocumentOutput>('doc:save')
```

### 2. Error Boundaries

```tsx
function DocumentEditor() {
  const saveDoc = useCommand('doc:save', {
    onError: (error, input) => {
      // Log para monitoramento
      logger.error('Save failed', { 
        error: error.message,
        documentId: input?.id 
      })
      
      // Fallback local
      localStorage.setItem('unsaved_doc', JSON.stringify(input))
    }
  })
}
```

### 3. Loading States Granulares

```tsx
function MultiStepForm() {
  const validateStep = useCommand('form:validate-step', { trackState: true })
  const submitForm = useCommand('form:submit', { trackState: true })
  
  const isValidating = validateStep.isLoading
  const isSubmitting = submitForm.isLoading
  const isProcessing = isValidating || isSubmitting
  
  return (
    <form>
      {/* Campos do formulário */}
      
      <button 
        type="button"
        onClick={() => validateStep.invoke({ step: currentStep })}
        disabled={isProcessing}
      >
        {isValidating ? 'Validando...' : 'Validar Etapa'}
      </button>
      
      <button 
        type="submit"
        onClick={() => submitForm.invoke(formData)}
        disabled={isProcessing || !isFormValid}
      >
        {isSubmitting ? 'Enviando...' : 'Enviar'}
      </button>
    </form>
  )
}
```

O `useCommand` é o hook mais poderoso e flexível do Commander, oferecendo controle total sobre execução, estado e comportamento dos comandos.