# 🚀 Sistema Compute - Campos Calculados Automáticos

## 📚 Índice
1. [Visão Geral](#visão-geral)
2. [Arquitetura](#arquitetura)
3. [Implementação](#implementação)
4. [Como Usar](#como-usar)
5. [Exemplos Práticos](#exemplos-práticos)
6. [Configuração Avançada](#configuração-avançada)
7. [Troubleshooting](#troubleshooting)
8. [Melhorias Futuras](#melhorias-futuras)

---

## 🎯 Visão Geral

O sistema `compute` é uma solução **dinâmica e reutilizável** para campos calculados automaticamente em formulários Angular. Ele permite que campos sejam calculados em tempo real baseado em outros campos do formulário, sem necessidade de código específico por domínio.

### ✨ Características Principais
- ✅ **100% Reutilizável** para qualquer domínio
- ✅ **Detecção automática** de dependências
- ✅ **Recálculo em tempo real** quando campos relacionados mudam
- ✅ **Configuração declarativa** por campo
- ✅ **Performance otimizada** com listeners inteligentes
- ✅ **Tratamento de erros** robusto

---

## 🏗️ Arquitetura

### 📁 Estrutura de Arquivos
```
projects/idt_app/src/app/shared/
├── interfaces/
│   └── generic-tab-form.interface.ts    # Interface TabFormField estendida
└── components/
    └── generic-tab-form/
        └── generic-tab-form.component.ts # Lógica de campos computados
```

### 🔧 Componentes do Sistema
1. **Interface Estendida**: `TabFormField` com propriedades `compute` e `computeDependencies`
2. **Detector de Dependências**: Analisa funções `compute` automaticamente
3. **Listener Dinâmico**: Escuta mudanças apenas nos campos relevantes
4. **Calculador**: Executa funções `compute` e atualiza valores
5. **Gerenciador de Estado**: Preserva valores calculados durante edição

---

## 🚀 Implementação

### 1. Interface TabFormField Estendida

```typescript
// projects/idt_app/src/app/shared/interfaces/generic-tab-form.interface.ts

export interface TabFormField {
  // ... propriedades existentes ...
  
  // 🎯 NOVA: Propriedade para campos calculados
  compute?: (model: any) => any;
  
  // 🎯 NOVA: Dependências para campos computados
  computeDependencies?: string[];
}
```

**Propriedades:**
- `compute`: Função que calcula o valor do campo
- `computeDependencies`: Array de nomes dos campos que afetam o cálculo

### 2. Sistema de Detecção Automática

```typescript
// projects/idt_app/src/app/shared/components/generic-tab-form/generic-tab-form.component.ts

private getAllComputedFieldDependencies(): string[] {
  const allFields = this.getAllFieldsFromSubTabs();
  const dependencies = new Set<string>();
  
  allFields.forEach(field => {
    if (field.compute) {
      // 🎯 Dependências explícitas (declaradas pelo desenvolvedor)
      if (field.computeDependencies) {
        field.computeDependencies.forEach(dep => dependencies.add(dep));
      }
      
      // 🚀 DETECÇÃO AUTOMÁTICA: Analisar a função compute
      const autoDependencies = this.detectDependenciesFromComputeFunction(field);
      autoDependencies.forEach(dep => dependencies.add(dep));
    }
  });
  
  return Array.from(dependencies);
}
```

### 3. Detecção Inteligente de Dependências

```typescript
private detectDependenciesFromComputeFunction(field: TabFormField): string[] {
  if (!field.compute) return [];
  
  try {
    const functionString = field.compute.toString();
    const dependencies: string[] = [];
    
    // 🎯 Padrões comuns de acesso a propriedades
    const patterns = [
      /model\.(\w+)/g,           // model.propertyName
      /model\?\.(\w+)/g,         // model?.propertyName
      /model\[['"`](\w+)['"`]\]/g, // model['propertyName']
      /model\[`(\w+)`\]/g        // model[`propertyName`]
    ];
    
    patterns.forEach(pattern => {
      let match;
      while ((match = pattern.exec(functionString)) !== null) {
        const propertyName = match[1];
        if (propertyName && !dependencies.includes(propertyName)) {
          dependencies.push(propertyName);
        }
      }
    });
    
    return dependencies;
  } catch (error) {
    console.warn(`⚠️ Erro ao detectar dependências automáticas para ${field.key}:`, error);
    return [];
  }
}
```

### 4. Listener Dinâmico

```typescript
private setupComputedFieldsListener(): void {
  if (!this.form) return;
  
  // 🚀 DINÂMICO: Detectar automaticamente todas as dependências
  const allDependencies = this.getAllComputedFieldDependencies();
  
  if (allDependencies.length === 0) {
    console.log('ℹ️ [COMPUTE] Nenhum campo computado encontrado');
    return;
  }
  
  console.log('🎯 [COMPUTE] Dependências detectadas:', allDependencies);
  
  // Escutar mudanças em TODOS os campos que afetam cálculos
  this.form.valueChanges.subscribe(value => {
    const hasRelevantChange = allDependencies.some(field => 
      value[field] !== undefined && value[field] !== null
    );
    
    if (hasRelevantChange) {
      this.updateComputedFields();
    }
  });
}
```

### 5. Atualização de Campos Computados

```typescript
private updateComputedFields(): void {
  if (!this.form) return;
  
  const formValue = this.form.value;
  
  this.getAllFieldsFromSubTabs().forEach(field => {
    if (field.compute) {
      try {
        const computedValue = field.compute(formValue);
        if (computedValue !== undefined && computedValue !== null) {
          this.form.get(field.key)?.setValue(computedValue, { emitEvent: false });
        }
      } catch (error) {
        console.warn(`⚠️ Erro ao recalcular campo ${field.key}:`, error);
      }
    }
  });
}
```

---

## 📝 Como Usar

### 1. Configuração Básica de Campo Computado

```typescript
{
  key: 'campo_calculado',
  label: 'Campo Calculado',
  type: 'number',
  readOnly: true,
  compute: (model: any) => {
    // Lógica de cálculo aqui
    return resultado;
  },
  computeDependencies: ['campo1', 'campo2']
}
```

### 2. Tipos de Campo Suportados

```typescript
// ✅ Tipos que funcionam bem com compute
type: 'number'           // Para valores numéricos
type: 'currency-input'   // Para valores monetários
type: 'text'             // Para texto calculado
type: 'date'             // Para datas calculadas
```

### 3. Estrutura da Função Compute

```typescript
compute: (model: any) => {
  // 🎯 model contém todos os valores do formulário
  
  // 🎯 Acessar campos específicos
  const valor1 = Number(model?.campo1) || 0;
  const valor2 = Number(model?.campo2) || 0;
  
  // 🎯 Lógica de cálculo
  const resultado = valor1 + valor2;
  
  // 🎯 Retornar o valor calculado
  return resultado;
}
```

---

## 💡 Exemplos Práticos

### 1. Cálculo Financeiro (Veículos)

```typescript
{
  key: 'calc_total_pago',
  label: 'Valor Total Pago',
  type: 'currency-input',
  readOnly: true,
  compute: (model: any) => {
    const parcela = Number(model?.alienation_payment_installment_value) || 0;
    const pagas = Number(model?.alienation_payment_installment_total) || 0;
    return parcela * pagas;
  },
  computeDependencies: ['alienation_payment_installment_value', 'alienation_payment_installment_total'],
  formatOptions: { locale: 'pt-BR', useGrouping: true, suffix: ' R$' }
}
```

### 2. Cálculo de Idade (Motoristas)

```typescript
{
  key: 'idade_calculada',
  label: 'Idade',
  type: 'number',
  readOnly: true,
  compute: (model: any) => {
    if (!model?.data_nascimento) return null;
    
    const nascimento = new Date(model.data_nascimento);
    const hoje = new Date();
    const idade = hoje.getFullYear() - nascimento.getFullYear();
    
    // Ajustar para mês/dia
    const mesAtual = hoje.getMonth();
    const mesNascimento = nascimento.getMonth();
    
    if (mesAtual < mesNascimento || 
        (mesAtual === mesNascimento && hoje.getDate() < nascimento.getDate())) {
      return idade - 1;
    }
    
    return idade;
  },
  computeDependencies: ['data_nascimento']
}
```

### 3. Formatação de CNPJ (Empresas)

```typescript
{
  key: 'cnpj_formatado',
  label: 'CNPJ Formatado',
  type: 'text',
  readOnly: true,
  compute: (model: any) => {
    const cnpj = model?.cnpj;
    if (!cnpj) return '';
    
    // Remover caracteres não numéricos
    const cleanCnpj = cnpj.replace(/\D/g, '');
    
    if (cleanCnpj.length !== 14) return cnpj;
    
    // Formatar: XX.XXX.XXX/XXXX-XX
    return cleanCnpj.replace(
      /(\d{2})(\d{3})(\d{3})(\d{4})(\d{2})/,
      '$1.$2.$3/$4-$5'
    );
  },
  computeDependencies: ['cnpj']
}
```

### 4. Cálculo de Distância (Rotas)

```typescript
{
  key: 'distancia_total',
  label: 'Distância Total',
  type: 'number',
  readOnly: true,
  compute: (model: any) => {
    const paradas = model?.stops || [];
    
    if (paradas.length < 2) return 0;
    
    let distanciaTotal = 0;
    
    for (let i = 1; i < paradas.length; i++) {
      const anterior = paradas[i - 1];
      const atual = paradas[i];
      
      const distancia = this.calcularDistancia(
        anterior.latitude, anterior.longitude,
        atual.latitude, atual.longitude
      );
      
      distanciaTotal += distancia;
    }
    
    return Math.round(distanciaTotal * 100) / 100; // 2 casas decimais
  },
  computeDependencies: ['stops']
}
```

---

## ⚙️ Configuração Avançada

### 1. Dependências Múltiplas

```typescript
{
  key: 'campo_complexo',
  compute: (model: any) => {
    // Campo depende de vários outros campos
    const valor1 = model?.campo1 || 0;
    const valor2 = model?.campo2 || 0;
    const valor3 = model?.campo3 || 0;
    
    return (valor1 + valor2) * valor3;
  },
  // 🎯 Declarar TODAS as dependências
  computeDependencies: ['campo1', 'campo2', 'campo3']
}
```

### 2. Validação Condicional

```typescript
{
  key: 'campo_validado',
  compute: (model: any) => {
    const valor = model?.campo_base;
    
    // 🎯 Validação antes do cálculo
    if (!valor || valor <= 0) {
      return null; // Retornar null para indicar valor inválido
    }
    
    return valor * 2;
  },
  computeDependencies: ['campo_base']
}
```

### 3. Cálculos com Formatação

```typescript
{
  key: 'valor_formatado',
  type: 'text',
  readOnly: true,
  compute: (model: any) => {
    const valor = Number(model?.valor_base) || 0;
    
    if (valor === 0) return 'R$ 0,00';
    
    // 🎯 Formatação brasileira
    return valor.toLocaleString('pt-BR', {
      style: 'currency',
      currency: 'BRL',
      minimumFractionDigits: 2
    });
  },
  computeDependencies: ['valor_base']
}
```

---

## 🔧 Troubleshooting

### ❌ Problemas Comuns e Soluções

#### 1. Campo não está sendo recalculado

**Sintomas:**
- Campo computado não atualiza quando dependências mudam
- Valor inicial não é calculado

**Soluções:**
```typescript
// ✅ Verificar se computeDependencies está correto
computeDependencies: ['campo1', 'campo2']

// ✅ Verificar se a função compute retorna valor válido
compute: (model: any) => {
  const valor = model?.campo1 || 0;
  return valor > 0 ? valor * 2 : 0; // Sempre retornar valor válido
}
```

#### 2. Erro "Cannot read property of undefined"

**Sintomas:**
- Erro no console ao tentar calcular campo
- Campo fica vazio

**Soluções:**
```typescript
// ✅ Usar operador de coalescência nula
compute: (model: any) => {
  const valor = model?.campo1 ?? 0; // Usar ?? em vez de ||
  return valor * 2;
}

// ✅ Verificar se campos existem antes de usar
compute: (model: any) => {
  if (!model?.campo1 || !model?.campo2) return 0;
  return model.campo1 + model.campo2;
}
```

#### 3. Performance lenta com muitos campos computados

**Sintomas:**
- Formulário lento ao digitar
- Muitos recálculos desnecessários

**Soluções:**
```typescript
// ✅ Limitar dependências apenas aos campos essenciais
computeDependencies: ['campo_essencial'] // Não incluir campos opcionais

// ✅ Usar debounce para campos que mudam frequentemente
// (Implementar no futuro se necessário)
```

### 🔍 Debug e Logs

```typescript
// ✅ Adicionar logs para debug
compute: (model: any) => {
  console.log('🔍 [DEBUG] Modelo recebido:', model);
  
  const valor1 = Number(model?.campo1) || 0;
  const valor2 = Number(model?.campo2) || 0;
  
  console.log('🔍 [DEBUG] Valores:', { valor1, valor2 });
  
  const resultado = valor1 + valor2;
  console.log('🔍 [DEBUG] Resultado:', resultado);
  
  return resultado;
}
```

---

## 🚀 Melhorias Futuras

### 1. Sistema de Cache Inteligente
```typescript
// 🎯 Cache configurável por campo
computeCache?: {
  enabled?: boolean;
  ttl?: number; // Time to live em ms
  strategy?: 'memory' | 'localStorage';
}
```

### 2. Debounce para Campos Frequentes
```typescript
// 🎯 Debounce para campos que mudam muito
computeDebounce?: {
  enabled?: boolean;
  delay?: number; // ms
}
```

### 3. Validação de Dependências
```typescript
// 🎯 Validação automática de dependências
computeValidation?: {
  required?: boolean;
  minValue?: number;
  maxValue?: number;
  pattern?: RegExp;
}
```

### 4. Métricas de Performance
```typescript
// 🎯 Monitoramento de performance
computeMetrics?: {
  trackExecutionTime?: boolean;
  trackDependencyChanges?: boolean;
  logPerformance?: boolean;
}
```

---

## ✅ Checklist de Implementação

### ✅ Para Desenvolvedores

- [ ] Campo tem propriedade `compute` definida
- [ ] Campo tem `computeDependencies` declaradas
- [ ] Campo é `readOnly: true`
- [ ] Função `compute` retorna valor válido
- [ ] Dependências estão corretas
- [ ] Tratamento de erros implementado
- [ ] Testado com valores vazios/nulos
- [ ] Performance aceitável

### ✅ Para Testes

- [ ] Campo é calculado ao carregar formulário
- [ ] Campo é recalculado quando dependências mudam
- [ ] Campo não é recalculado desnecessariamente
- [ ] Tratamento de erros funciona
- [ ] Performance é aceitável
- [ ] Funciona em diferentes domínios

---

## 🎯 Conclusão

O sistema `compute` para campos calculados é uma solução **robusta, escalável e reutilizável** que elimina a necessidade de código específico por domínio para cálculos automáticos.

### 🌟 Benefícios
- **Produtividade**: Desenvolvimento mais rápido
- **Manutenibilidade**: Código centralizado e limpo
- **Reutilização**: Funciona em qualquer domínio
- **Performance**: Otimizado e eficiente
- **Flexibilidade**: Configurável por campo

### 🎯 Próximos Passos
1. Implementar em novos domínios
2. Adicionar testes automatizados
3. Monitorar performance em produção
4. Coletar feedback dos usuários
5. Implementar melhorias baseadas em uso real

---

## 📚 Referências

### Arquivos do Sistema
- **Interface**: `projects/idt_app/src/app/shared/interfaces/generic-tab-form.interface.ts`
- **Componente**: `projects/idt_app/src/app/shared/components/generic-tab-form/generic-tab-form.component.ts`
- **Exemplo de Uso**: `projects/idt_app/src/app/domain/vehicles/vehicles.component.ts`

### Padrões Utilizados
- **Registry Pattern**: Para configuração de formulários
- **Observer Pattern**: Para listeners de mudanças
- **Strategy Pattern**: Para diferentes tipos de cálculo
- **Factory Pattern**: Para criação de campos computados

---

**Autor**: PraFrota Development Team  
**Data**: $(date)  
**Versão**: 2.0.0 - Padronização Completa 
