import * as XLSX from 'xlsx';
import { getDb } from './db';
import { formations as formationsTable, sequences as sequencesTable, datesFormation } from '../drizzle/schema';

export interface FormationImport {
  nom: string;
  description: string;
  publicCible: 'directeur' | 'chef_service' | 'tous' | 'autre';
}

export interface SequenceImport {
  formationNom: string;
  nom: string;
  lieu: string;
  publicCible: 'directeur' | 'chef_service' | 'tous' | 'autre';
  capaciteMax: number;
  dateBlocage: string;
  statut: 'ouverte' | 'bloquee' | 'terminee';
  dates: Array<{ debut: string; fin: string }>;
}

export interface ImportResult {
  success: boolean;
  formationsCreated: number;
  sequencesCreated: number;
  errors: string[];
  warnings: string[];
}

/**
 * Parse un fichier Excel et retourne les données structurées
 */
export function parseExcelFile(buffer: Buffer): { formations: FormationImport[]; sequences: SequenceImport[] } {
  const workbook = XLSX.read(buffer, { type: 'buffer' });
  
  const formations: FormationImport[] = [];
  const sequences: SequenceImport[] = [];

  // Parser la feuille "Formations"
  if (workbook.SheetNames.includes('Formations')) {
    const sheet = workbook.Sheets['Formations'];
    const data = XLSX.utils.sheet_to_json<any>(sheet, { header: 1 });
    
    // Ignorer la première ligne (en-têtes) et les lignes vides
    for (let i = 1; i < data.length; i++) {
      const row = data[i];
      if (!row || row.length === 0 || !row[0]) continue;
      
      // Arrêter si on atteint les instructions
      if (String(row[0]).toUpperCase().includes('INSTRUCTIONS')) break;
      
      formations.push({
        nom: String(row[0] || '').trim(),
        description: String(row[1] || '').trim(),
        publicCible: normalizePublicCible(String(row[2] || '').trim()),
      });
    }
  }

  // Parser la feuille "Séquences"
  if (workbook.SheetNames.includes('Séquences')) {
    const sheet = workbook.Sheets['Séquences'];
    const data = XLSX.utils.sheet_to_json<any>(sheet, { header: 1 });
    
    for (let i = 1; i < data.length; i++) {
      const row = data[i];
      if (!row || row.length === 0 || !row[0]) continue;
      
      // Arrêter si on atteint les instructions
      if (String(row[0]).toUpperCase().includes('INSTRUCTIONS')) break;
      
      const dates: Array<{ debut: string; fin: string }> = [];
      
      // Parser les 4 dates possibles (colonnes 7-14)
      for (let d = 0; d < 4; d++) {
        const debutIdx = 7 + (d * 2);
        const finIdx = 8 + (d * 2);
        
        if (row[debutIdx] && row[finIdx]) {
          dates.push({
            debut: parseExcelDate(row[debutIdx]),
            fin: parseExcelDate(row[finIdx]),
          });
        }
      }
      
      sequences.push({
        formationNom: String(row[0] || '').trim(),
        nom: String(row[1] || '').trim(),
        lieu: String(row[2] || '').trim(),
        publicCible: normalizePublicCible(String(row[3] || '').trim()),
        capaciteMax: parseInt(String(row[4] || '12')),
        dateBlocage: parseExcelDate(row[5]),
        statut: normalizeStatut(String(row[6] || '').trim()),
        dates,
      });
    }
  }

  return { formations, sequences };
}

/**
 * Valide les données importées
 */
export function validateImportData(
  formations: FormationImport[],
  sequences: SequenceImport[]
): { valid: boolean; errors: string[]; warnings: string[] } {
  const errors: string[] = [];
  const warnings: string[] = [];

  // Valider les formations
  formations.forEach((formation, index) => {
    if (!formation.nom) {
      errors.push(`Formation ligne ${index + 2}: Le nom est obligatoire`);
    }
    if (!formation.description) {
      errors.push(`Formation ligne ${index + 2}: La description est obligatoire`);
    }
    if (!['directeur', 'chef_service', 'tous', 'autre'].includes(formation.publicCible)) {
      errors.push(`Formation ligne ${index + 2}: Public cible invalide (${formation.publicCible})`);
    }
  });

  // Créer un set des noms de formations pour validation des séquences
  const formationNames = new Set(formations.map(f => f.nom.toLowerCase()));

  // Valider les séquences
  sequences.forEach((sequence, index) => {
    if (!sequence.formationNom) {
      errors.push(`Séquence ligne ${index + 2}: Le nom de la formation est obligatoire`);
    } else if (!formationNames.has(sequence.formationNom.toLowerCase())) {
      errors.push(`Séquence ligne ${index + 2}: Formation "${sequence.formationNom}" non trouvée dans la feuille Formations`);
    }
    
    if (!sequence.nom) {
      errors.push(`Séquence ligne ${index + 2}: Le nom est obligatoire`);
    }
    if (!sequence.lieu) {
      errors.push(`Séquence ligne ${index + 2}: Le lieu est obligatoire`);
    }
    if (!['directeur', 'chef_service', 'tous', 'autre'].includes(sequence.publicCible)) {
      errors.push(`Séquence ligne ${index + 2}: Public cible invalide`);
    }
    if (!sequence.dateBlocage) {
      errors.push(`Séquence ligne ${index + 2}: La date de blocage est obligatoire`);
    }
    if (!['ouverte', 'bloquee', 'terminee'].includes(sequence.statut)) {
      errors.push(`Séquence ligne ${index + 2}: Statut invalide`);
    }
    if (sequence.dates.length === 0) {
      errors.push(`Séquence ligne ${index + 2}: Au moins une date est obligatoire`);
    }
    if (sequence.dates.length > 4) {
      warnings.push(`Séquence ligne ${index + 2}: Maximum 4 dates autorisées, les dates supplémentaires seront ignorées`);
    }
  });

  return {
    valid: errors.length === 0,
    errors,
    warnings,
  };
}

/**
 * Importe les données dans la base de données
 */
export async function importToDatabase(
  formations: FormationImport[],
  sequences: SequenceImport[]
): Promise<ImportResult> {
  const db = await getDb();
  if (!db) {
    return {
      success: false,
      formationsCreated: 0,
      sequencesCreated: 0,
      errors: ['Connexion à la base de données impossible'],
      warnings: [],
    };
  }

  const errors: string[] = [];
  const warnings: string[] = [];
  let formationsCreated = 0;
  let sequencesCreated = 0;

  try {
    // Map pour stocker les IDs des formations créées
    const formationIdMap = new Map<string, number>();

    // Importer les formations
    console.log(`[Import] Début import de ${formations.length} formations`);
    for (const formation of formations) {
      try {
        console.log(`[Import] Création formation: ${formation.nom}`);
        const [result] = await db.insert(formationsTable).values({
          nom: formation.nom,
          description: formation.description,
          lienUnique: generateUniqueLien(),
        }).$returningId();
        
        const formationId = result.id;
        formationIdMap.set(formation.nom.toLowerCase(), formationId);
        console.log(`[Import] Formation créée avec ID ${formationId}, ajoutée à la map avec clé: "${formation.nom.toLowerCase()}"`);
        formationsCreated++;
      } catch (error: any) {
        console.error(`[Import] Erreur formation "${formation.nom}":`, error);
        errors.push(`Erreur lors de la création de la formation "${formation.nom}": ${error.message}`);
      }
    }
    console.log(`[Import] Formations créées: ${formationsCreated}, Map size: ${formationIdMap.size}`);
    console.log(`[Import] Clés dans la map:`, Array.from(formationIdMap.keys()));

    // Si des erreurs sont survenues lors de la création des formations, arrêter l'import
    if (errors.length > 0) {
      console.error(`[Import] Arrêt de l'import car ${errors.length} erreur(s) lors de la création des formations`);
      return {
        success: false,
        formationsCreated,
        sequencesCreated: 0,
        errors,
        warnings,
      };
    }

    // Importer les séquences
    console.log(`[Import] Début import de ${sequences.length} séquences`);
    for (const sequence of sequences) {
      try {
        const searchKey = sequence.formationNom.toLowerCase();
        console.log(`[Import] Recherche formation pour séquence "${sequence.nom}" avec clé: "${searchKey}"`);
        const formationId = formationIdMap.get(searchKey);
        if (!formationId) {
          errors.push(`Formation "${sequence.formationNom}" non trouvée pour la séquence "${sequence.nom}"`);
          continue;
        }

        const [result] = await db.insert(sequencesTable).values({
          formationId,
          nom: sequence.nom,
          lieu: sequence.lieu,
          publicCible: sequence.publicCible,
          capaciteMax: sequence.capaciteMax,
          dateBlocage: new Date(sequence.dateBlocage),
          statut: sequence.statut,
        }).$returningId();

        const sequenceId = result.id;

        // Insérer les dates de formation
        for (let i = 0; i < Math.min(sequence.dates.length, 4); i++) {
          const date = sequence.dates[i];
          await db.insert(datesFormation).values({
            sequenceId,
            dateDebut: new Date(date.debut),
            dateFin: new Date(date.fin),
            ordre: i + 1,
          });
        }

        sequencesCreated++;
      } catch (error: any) {
        errors.push(`Erreur lors de la création de la séquence "${sequence.nom}": ${error.message}`);
      }
    }

    return {
      success: errors.length === 0,
      formationsCreated,
      sequencesCreated,
      errors,
      warnings,
    };
  } catch (error: any) {
    return {
      success: false,
      formationsCreated,
      sequencesCreated,
      errors: [`Erreur générale: ${error.message}`],
      warnings,
    };
  }
}

/**
 * Normalise le public cible
 */
function normalizePublicCible(value: string): 'directeur' | 'chef_service' | 'tous' | 'autre' {
  const normalized = value.toLowerCase().trim();
  if (normalized === 'directeur') return 'directeur';
  if (normalized === 'chef_service' || normalized === 'chef de service') return 'chef_service';
  if (normalized === 'tous') return 'tous';
  return 'autre';
}

/**
 * Normalise le statut
 */
function normalizeStatut(value: string): 'ouverte' | 'bloquee' | 'terminee' {
  const normalized = value.toLowerCase().trim();
  if (normalized === 'ouverte') return 'ouverte';
  if (normalized === 'bloquee' || normalized === 'bloquée') return 'bloquee';
  if (normalized === 'terminee' || normalized === 'terminée') return 'terminee';
  return 'ouverte';
}

/**
 * Parse une date Excel (peut être un nombre de série Excel ou une chaîne)
 */
function parseExcelDate(value: any): string {
  if (!value) return '';
  
  // Si c'est un nombre (date Excel)
  if (typeof value === 'number') {
    const date = XLSX.SSF.parse_date_code(value);
    return `${date.y}-${String(date.m).padStart(2, '0')}-${String(date.d).padStart(2, '0')} ${String(date.H || 0).padStart(2, '0')}:${String(date.M || 0).padStart(2, '0')}`;
  }
  
  // Si c'est déjà une chaîne
  return String(value).trim();
}

/**
 * Génère un lien unique pour une formation
 */
function generateUniqueLien(): string {
  return Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
}
