import { Meta, Source } from '@storybook/addon-docs/blocks';
import '../styles/shared.css';

<Meta title="Guide Du Dev/Guide Technique - Système de Validation & Règles"/>


<div className="header">
  <h1>Guide Technique</h1>
  <h2>Système de Validation & Règles</h2>
  <p>Ce guide technique explique le fonctionnement interne du système de validation, la création de règles personnalisées et les cas d'usage avancés.</p>
  
  <div className="guide-links">
    <p>📖 <strong>Guides complémentaires :</strong></p>
    <ul>
      <li><a href="?path=/docs/guide-du-dev-guide-des-formulaires-syform-validation-automatique--docs">Guide des Formulaires - SyForm & Validation Automatique</a> (approche recommandée)</li>
    </ul>
  </div>
</div>

## Architecture du système

Le système de validation repose sur deux composables principaux :

### `useFieldValidation`
- **Rôle** : Génère et exécute les règles de validation
- **Usage** : Création de règles personnalisées, validation de champs individuels
- **Retour** : Fonctions de validation prêtes à l'emploi

### `useValidation` 
- **Rôle** : Gère l'état de validation et l'affichage des messages
- **Usage** : Intégration dans les composants, gestion des états d'erreur/warning/succès
- **Retour** : État réactif et méthodes de validation

### Priorité des validations

Le système suit une hiérarchie stricte :
1. **Erreurs** 🔴 → Bloquent la soumission, priorité absolue
2. **Avertissements** 🟠 → Informent sans bloquer, priorité moyenne  
3. **Succès** 🟢 → Encouragent l'utilisateur, priorité faible

> **Note** : Cette hiérarchie est automatiquement gérée par `useValidation`

## Structure des types

### Type `ValidationOptions`

Options de configuration pour la validation :

<Source dark code={`
interface ValidationOptions {
  showSuccessMessages?: boolean;  // Activer/désactiver les messages de succès
  fieldIdentifier?: string;       // Nom du champ pour les messages
  customRules?: ValidationRule[]; // Règles personnalisées
  warningRules?: ValidationRule[]; // Règles d'avertissement
  successRules?: ValidationRule[]; // Règles de succès
  disableErrorHandling?: boolean; // Désactiver complètement la gestion des erreurs
}
`}/>

### Type `ValidationRule`

Structure d'une règle de validation :

<Source dark code={`
type ValidationRule = {
  type: string;     // Type de règle (ex: 'required', 'email')
  options: RuleOptions;
}
`}/>

### Type `RuleOptions`

Options disponibles pour configurer une règle :

<Source dark code={`
interface RuleOptions {
  message?: string;         // Message d'erreur personnalisé
  successMessage?: string;  // Message de succès personnalisé
  warningMessage?: string;  // Message d'avertissement personnalisé
  fieldName?: string;      // Nom du champ pour les messages
  fieldIdentifier?: string; // Identifiant du champ
  value?: any;             // Valeur pour les règles min/max
  length?: number;         // Longueur pour minLength/maxLength
  pattern?: RegExp;        // Expression régulière
  ignoreSpace?: boolean;   // Ignorer les espaces
  isWarning?: boolean;     // Traiter comme un avertissement
  validate?: (value: any) => boolean | string; // Validation personnalisée
  date?: string | Date;    // Date de référence pour les règles de dates
}
`}/>

## Validation manuelle avec useValidation

Quand SyForm ne suffit pas (composants tiers, logique complexe), utilisez directement `useValidation` :

<Source dark code={`
<script lang="ts" setup>
import { ref } from 'vue'
import { useValidation } from '@cnamts/synapse'

const password = ref('')

const { validateField, hasError, hasWarning, hasSuccess, errors, warnings, successes } = useValidation({
  fieldIdentifier: 'Mot de passe',
  showSuccessMessages: true
})

// Règles d'erreur (bloquantes)
const errorRules = [
  { 
    type: 'required',
    options: { message: 'Le mot de passe est requis' }
  },
  { 
    type: 'minLength',
    options: { length: 6, message: 'Le mot de passe doit contenir au moins 6 caractères' }
  }
]

// Règles d'avertissement (non-bloquantes)
const warningRules = [
  {
    type: 'minLength',
    options: { 
      length: 8,
      warningMessage: 'Un mot de passe de 8 caractères minimum est recommandé'
    }
  }
]

// Règles de succès (messages positifs)
const successRules = [
  {
    type: 'minLength',
    options: { 
      length: 12,
      successMessage: 'Excellent ! Votre mot de passe est très sécurisé'
    }
  }
]

const validate = () => {
  const result = validateField(
    password.value,
    errorRules,
    warningRules,
    successRules
  )
  
  // result contient :
  // - hasError: boolean
  // - hasWarning: boolean
  // - hasSuccess: boolean
  // - state: { errors, warnings, successes }
}
</script>

<template>
  <div>
    <input 
      v-model="password"
      @input="validate"
      :class="{ 
        'error': hasError,
        'warning': hasWarning && !hasError,
        'success': hasSuccess
      }"
    />
    
    <!-- Affichage des messages -->
    <div v-if="hasError" class="error-messages">
      <p v-for="error in errors" :key="error">{{ error }}</p>
    </div>
    
    <div v-else-if="hasWarning" class="warning-messages">
      <p v-for="warning in warnings" :key="warning">{{ warning }}</p>
    </div>
    
    <div v-else-if="hasSuccess" class="success-messages">
      <p v-for="success in successes" :key="success">{{ success }}</p>
    </div>
  </div>
</template>
`}/>

## Création de règles personnalisées

Pour créer vos propres règles de validation, utilisez le type `custom` :

### Règle simple avec validation booléenne

<Source dark code={`
const passwordStrengthRule = {
  type: 'custom',
  options: {
    validate: (value: string) => {
      const hasNumber = /\d/.test(value);
      const hasUpper = /[A-Z]/.test(value);
      const hasLower = /[a-z]/.test(value);
      const hasSpecial = /[!@#$%^&*(),.?":{}|<>]/.test(value);
      
      // Retourne true si valide, false sinon
      return hasNumber && hasUpper && hasLower && hasSpecial;
    },
    message: 'Le mot de passe doit contenir au moins un chiffre, une majuscule, une minuscule et un caractère spécial',
    successMessage: 'Mot de passe sécurisé ✓'
  }
};
`}/>

### Règle avancée avec message conditionnel

<Source dark code={`
const emailDomainRule = {
  type: 'custom',
  options: {
    validate: (value: string) => {
      if (!value) return true; // Laisser 'required' gérer les champs vides
      
      if (!value.includes('@')) {
        return 'Format d\'email invalide';
      }
      
      const [localPart, domain] = value.split('@');
      
      if (!domain) {
        return 'Domaine manquant dans l\'email';
      }
      
      if (!domain.endsWith('.fr')) {
        return 'Seuls les domaines .fr sont autorisés';
      }
      
      if (domain === 'ameli.fr' && !/^[a-z]+\.[a-z]+$/.test(localPart)) {
        return 'Format ameli.fr requis : prenom.nom@ameli.fr';
      }
      
      return true; // Validation réussie
    },
    fieldIdentifier: 'Email professionnel'
  }
};
`}/>

### Règle avec état externe et réactivité

<Source dark code={`
// Règle qui dépend d'un état externe (ex: liste d'utilisateurs existants)
const userList = ref(['jean.dupont', 'marie.martin', 'pierre.durand']);

const uniqueUsernameRule = computed(() => ({
  type: 'custom',
  options: {
    validate: (value: string) => {
      if (!value) return true;
      
      const normalizedValue = value.toLowerCase().trim();
      
      if (userList.value.includes(normalizedValue)) {
        return 'Ce nom d\'utilisateur est déjà pris';
      }
      
      return true;
    },
    message: 'Nom d\'utilisateur indisponible',
    successMessage: 'Nom d\'utilisateur disponible ✓'
  }
}));

// Usage avec computed pour la réactivité
const usernameRules = computed(() => [
  { type: 'required', options: { message: 'Nom d\'utilisateur requis' } },
  { type: 'minLength', options: { length: 3, message: 'Minimum 3 caractères' } },
  uniqueUsernameRule.value // Règle réactive
]);
`}/>

### Règles asynchrones (validation serveur)

<Source dark code={`
const asyncEmailRule = {
  type: 'custom',
  options: {
    validate: async (value: string) => {
      if (!value || !value.includes('@')) return true;
      
      try {
        // Simulation d'un appel API
        const response = await fetch(\`/api/check-email?email=\${encodeURIComponent(value)}\`);
        const result = await response.json();
        
        if (!result.available) {
          return 'Cette adresse email est déjà utilisée';
        }
        
        return true;
      } catch (error) {
        // En cas d'erreur réseau, on ne bloque pas
        console.warn('Impossible de vérifier l\'email:', error);
        return true;
      }
    },
    message: 'Email déjà utilisé',
    successMessage: 'Email disponible'
  }
};
`}/>

## Règles de validation disponibles

### Règles basiques
- `required` : Vérifie qu'une valeur est présente
- `min` : Vérifie qu'une valeur numérique est supérieure ou égale à un minimum
- `max` : Vérifie qu'une valeur numérique est inférieure ou égale à un maximum
- `minLength` : Vérifie qu'une chaîne a une longueur minimale
- `maxLength` : Vérifie qu'une chaîne a une longueur maximale
- `exactLength` : Vérifie qu'une chaîne a une longueur exacte
- `email` : Vérifie qu'une chaîne est un email valide
- `matchPattern` : Vérifie qu'une chaîne correspond à une expression régulière

### Règles de validation de dates
- `notWeekend` : Vérifie qu'une date n'est pas un jour de week-end
- `notBeforeToday` : Vérifie qu'une date n'est pas antérieure à aujourd'hui
- `notAfterToday` : Vérifie qu'une date n'est pas postérieure à aujourd'hui
- `notBeforeDate` : Vérifie qu'une date n'est pas antérieure à une date de référence
- `notAfterDate` : Vérifie qu'une date n'est pas postérieure à une date de référence
- `dateExact` : Vérifie qu'une date est exactement égale à une date de référence

### Règle personnalisée
- `custom` : Permet de définir une validation personnalisée via la fonction `validate`

## Méthodes disponibles

Le composable `useValidation` retourne plusieurs méthodes utiles :

- `validateField` : Valide une valeur selon les règles définies
- `validateOnSubmit` : Vérifie si le formulaire peut être soumis (retourne `true` si aucune erreur)
- `clearValidation` : Réinitialise l'état de validation (efface erreurs, avertissements et succès)

## Bonnes pratiques

1. **Messages clairs** : Utilisez des messages explicites qui guident l'utilisateur
2. **Validation progressive** : Validez au fur et à mesure de la saisie
3. **Avertissements utiles** : Utilisez les warnings pour des recommandations non-bloquantes
4. **Messages de succès** : Encouragez les bonnes pratiques avec des messages positifs
5. **Identifiants de champs** : Utilisez `fieldIdentifier` pour des messages contextuels

> **⚠️ Important — Ordre des règles :** placez toujours `required` en dernier dans la liste de vos règles !
> Les règles sont évaluées dans l'ordre de leur déclaration, et la validation s'arrête dès qu'une erreur est rencontrée.
> Si `required` est positionné en premier et que l'utilisateur saisit une valeur (même invalide), la validation s'arrêtera immédiatement.
> En revanche, en le plaçant en dernier, si une autre règle échoue avant, l'utilisateur obtiendra le message d'erreur le plus pertinent.

## Exemple de validation personnalisée

<Source dark code={`
const customRules = [
  {
    type: 'custom',
    options: {
      validate: (value: string) => {
        const hasNumber = /\d/.test(value)
        const hasUpper = /[A-Z]/.test(value)
        const hasLower = /[a-z]/.test(value)
        
        if (!hasNumber || !hasUpper || !hasLower) {
          return 'Le mot de passe doit contenir au moins un chiffre, une majuscule et une minuscule'
        }
        
        return true
      },
      successMessage: 'Votre mot de passe respecte les critères de sécurité'
    }
  }
]
`}/>

## Conclusion

Le système de validation du Design System offre une grande flexibilité tout en restant simple à utiliser. La combinaison des erreurs, avertissements et succès permet de créer une expérience utilisateur riche et intuitive.
