const fs = require('fs');
const path = require('path');
const XLSX = require('xlsx');
const { getCompressedDefaultImage } = require('../function/GetImageDefaault');
const { parse } = require('csv-parse/sync');
const { pool } = require('../database');
const dayjs = require('dayjs');
const customParseFormat = require('dayjs/plugin/customParseFormat');
dayjs.extend(customParseFormat);

// ✅ Fonction de correction d'encodage
function fixEncoding(str) {
  if (typeof str !== 'string') return str;
  return str
    .replace(/├®/g, 'é')
    .replace(/├à/g, 'à')
    .replace(/├©/g, 'é')
    .replace(/├ô/g, 'ô')
    .replace(/├ù/g, 'ù')
    .replace(/â€™/g, "'")
    .replace(/â€/g, '…')
    .replace(/â€/g, '-');
}
function convertToISODate(input) {
  if (!input) return null;

  console.log('🔍 Input original:', input, 'Type:', typeof input);

  // Si input est un objet Date valide
  if (input instanceof Date && !isNaN(input)) {
    const result = dayjs(input).format('YYYY-MM-DD');
    console.log('📅 Date object convertie:', result);
    return result;
  }

  // Si input est un nombre (numéro de série Excel)
  if (typeof input === 'number') {
    // Formule Excel: (numéro - 25569) * 86400 * 1000
    const excelDate = new Date((input - 25569) * 86400 * 1000);
    const result = dayjs(excelDate).format('YYYY-MM-DD');
    console.log('📊 Numéro Excel', input, 'converti en:', result);
    return result;
  }

  // Si input est une chaîne
  if (typeof input === 'string') {
    const cleanInput = input.trim();
    
    // Cas spécial "vers YYYY"
    const versMatch = cleanInput.match(/vers\s*(\d{4})/i);
    if (versMatch) {
      const result = `${versMatch[1]}-01-01`;
      console.log('📝 "Vers" détecté:', result);
      return result;
    }

    // Formats à tester dans l'ordre de priorité
    const formats = [
      'DD/MM/YYYY', 'D/M/YYYY',      // Format français prioritaire
      'YYYY-MM-DD',                   // Format ISO
      'DD-MM-YYYY', 'D-M-YYYY',      // Format français avec tirets
      'MM/DD/YYYY', 'M/D/YYYY',      // Format américain
      'MM-DD-YYYY', 'M-D-YYYY',      // Format américain avec tirets
      'DD/MM/YY', 'D/M/YY',          // Années courtes
      'MM/DD/YY', 'M/D/YY',
      'DD-MM-YY', 'D-M-YY',
      'MM-DD-YY', 'M-D-YY'
    ];

    // Test avec parsing strict pour éviter les interprétations erronées
    for (const format of formats) {
      const parsedDate = dayjs(cleanInput, format, true); // true = strict parsing
      if (parsedDate.isValid()) {
        const result = parsedDate.format('YYYY-MM-DD');
        console.log(`✅ Format "${format}" réussi:`, cleanInput, '->', result);
        
        // Vérification supplémentaire pour les dates invalides comme 29/02 en année non-bissextile
        if (format.includes('DD/MM') || format.includes('D/M')) {
          const day = parsedDate.date();
          const month = parsedDate.month() + 1; // dayjs month is 0-indexed
          const year = parsedDate.year();
          
          // Vérifier si c'est le 29 février d'une année non-bissextile
          if (month === 2 && day === 29 && !isLeapYear(year)) {
            console.warn('⚠️  Date invalide détectée: 29 février en année non-bissextile');
            return null; // ou retourner une date par défaut
          }
        }
        
        return result;
      }
    }

    // Si aucun format strict ne fonctionne, essayer le parsing libre en dernier recours
    const freeParseDate = dayjs(cleanInput);
    if (freeParseDate.isValid()) {
      const result = freeParseDate.format('YYYY-MM-DD');
      console.log('🆓 Parsing libre réussi:', cleanInput, '->', result);
      return result;
    }
  }

  console.error('❌ Impossible de convertir:', input);
  return null;
}

// Fonction utilitaire pour vérifier les années bissextiles
function isLeapYear(year) {
  return (year % 4 === 0 && year % 100 !== 0) || (year % 400 === 0);
}

// ✅ Mise à jour d'un étudiant existant
async function updateEtudiant(row) {
  const sql = `
    UPDATE etudiants SET
      nom = ?,
      prenom = ?,
      photos = ?,
      date_de_naissances = ?,
      niveau = ?,
      annee_scolaire = ?,
      status = ?,
      mention_id = ?,
      num_inscription = ?,
      sexe = ?,
      date_delivrance = ?,
      nationalite = ?,
      annee_bacc = ?,
      serie = ?,
      boursier = ?,
      domaine = ?,
      contact = ?,
      parcours = ?
    WHERE cin = ? OR (LOWER(nom) = ? AND LOWER(prenom) = ?)
  `;

  const params = [
    row.nom,
    row.prenom,
    getCompressedDefaultImage(),
    convertToISODate(row.date_naissance),
    row.niveau,
    row.annee_scolaire,
    row.code_redoublement,
    row.mention,
    row.num_inscription.toString(),
    row.sexe,
    convertToISODate(row.date_de_delivrance),
    row.nationaliter,
    parseInt(row.annee_baccalaureat, 10),
    row.serie,
    row.boursier,
    fixEncoding(row.domaine),
    row.contact,
    null,
    row.cin,
    row.nom.toLowerCase().trim(),
    row.prenom.toLowerCase().trim()
  ];

  try {
    const [result] = await pool.query(sql, params);
    console.log(`Update effectué pour CIN ${row.cin} ou nom ${row.nom} ${row.prenom}, affectedRows=${result.affectedRows}`);
    return { success: true, affectedRows: result.affectedRows };
  } catch (error) {
    console.error('❌ Erreur MySQL update :', error.message);
    return { success: false, error: error.message };
  }
}


// ✅ Insertion réelle multiple
async function insertMultipleEtudiants(etudiants) {
  const sql = `
    INSERT INTO etudiants (
      nom, prenom, photos, date_de_naissances, niveau, annee_scolaire, status,
      mention_id, num_inscription, sexe, cin, date_delivrance, nationalite,
      annee_bacc, serie, boursier, domaine, contact, parcours
    ) VALUES ?
  `;

  const values = etudiants.map(row => [
    row.nom,
    row.prenom,
    getCompressedDefaultImage(),
    convertToISODate(row.date_naissance),
    row.niveau,
    row.annee_scolaire,
    row.code_redoublement,
    row.mention,
    row.num_inscription.toString(),
    row.sexe,
    row.cin,
    convertToISODate(row.date_de_delivrance),
    row.nationaliter,
    parseInt(row.annee_baccalaureat, 10),
    row.serie,
    row.boursier,
    fixEncoding(row.domaine),
    row.contact,
    null
  ]);

  try {
    const [result] = await pool.query(sql, [values]);
    return { success: true, affectedRows: result.affectedRows };
  } catch (error) {
    console.error('❌ Erreur MySQL :', error.message);
    return { success: false, error: error.message };
  }
}

// ✅ Import fichier vers base
async function importFileToDatabase(filePath) {
  const fileExtension = path.extname(filePath).toLowerCase();
  let records;

  if (fileExtension === '.xlsx') {
    const workbook = XLSX.readFile(filePath);
    const worksheet = workbook.Sheets[workbook.SheetNames[0]];
    // raw: true pour garder les valeurs brutes, surtout pour les dates
    records = XLSX.utils.sheet_to_json(worksheet, { defval: ''});
  } else if (fileExtension === '.csv') {
    const fileContent = fs.readFileSync(filePath, 'utf8');
    records = parse(fileContent, { columns: true, skip_empty_lines: true });
  }else {
    console.error('Unsupported file format.');
    return { error: true, message: 'Format de fichier non supporté.' };
  }

  console.log(`📄 Nombre de lignes : ${records.length}`);

  // Vérifier champs obligatoires
  const requiredFields = [
    'nom', 'date_naissance', 'niveau', 'annee_scolaire',
    'mention', 'num_inscription', 'nationaliter', 'sexe',
    'annee_baccalaureat', 'serie', 'code_redoublement',
    'boursier', 'domaine'
  ];

  for (const [i, row] of records.entries()) {
    for (const field of requiredFields) {
      if (!row[field]) {
        const msg = `Le champ '${field}' est manquant à la ligne ${i + 2}`;
        console.error(msg);
        return { error: true, message: msg };
      }
    }
  }

  const [mentionRows] = await pool.query('SELECT * FROM mentions');
  const [statusRows] = await pool.query('SELECT * FROM status');

  const etudiantsToInsert = [];
  const doublons = [];
  console.log(records);

  for (const row of records) {
    // Mapping mention
    console.log('Avant conversion date_naissance:', row.date_naissance);
    row.date_naissance = convertToISODate(row.date_naissance);
    console.log('Après conversion date_naissance:', row.date_naissance);
    const matchedMention = mentionRows.find(
      m => m.nom.toUpperCase() === row.mention.toUpperCase() ||
           m.uniter.toUpperCase() === row.mention.toUpperCase()
    );
    if (matchedMention) row.mention = matchedMention.id;

    // Gestion code_redoublement -> status id
    if (row.code_redoublement) {
      row.code_redoublement = row.code_redoublement.trim().substring(0, 1);
    } else {
      row.code_redoublement = 'N';
    }
    const statusMatch = statusRows.find(
      s => s.nom.toLowerCase().startsWith(row.code_redoublement.toLowerCase())
    );
    if (statusMatch) row.code_redoublement = statusMatch.id;

    // Vérification doublons (extraction complet)
    const nomComplet = (row.nom + ' ' + row.prenom).toLowerCase().trim();

    const [existing] = await pool.query(
      'SELECT * FROM etudiants WHERE LOWER(CONCAT(nom, " ", prenom)) = ? OR cin = ?',
      [nomComplet, row.cin]
    );

    if (existing.length > 0) {
      doublons.push({ nom: row.nom, prenom: row.prenom, cin: row.cin });
      // Mise à jour
      const updateResult = await updateEtudiant(row);
      if (!updateResult.success) {
        return { error: true, message: `Erreur lors de la mise à jour de ${row.nom} ${row.prenom} : ${updateResult.error}` };
      }
      continue;
    }

    etudiantsToInsert.push(row);
  }

  console.log(etudiantsToInsert);

  // Insertion des nouveaux
  let insertResult = { success: true, affectedRows: 0 };
  if (etudiantsToInsert.length > 0) {
    insertResult = await insertMultipleEtudiants(etudiantsToInsert);
    if (!insertResult.success) {
      return { error: true, message: `Erreur lors de l'insertion : ${insertResult.error}` };
    }
  }

  let msg = `Importation réussie. ${etudiantsToInsert.length} nouvel(le)(s) étudiant(s) inséré(s). ${doublons.length} étudiant(s) mis à jour.`;
  return { error: false, message: msg };
}

module.exports = { importFileToDatabase };
