import * as faceapi from '@vladmandic/face-api';
import sharp from 'sharp';
import pg from 'pg';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// Disable certificate verification for CDN download if needed
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '0';

const pool = new pg.Pool({
  connectionString: 'postgresql://edumanager:EduManager2026!Seguro@150.230.87.131:5432/edumanager'
});

async function run() {
  try {
    // 1. Initialize face-api environment for Node
    console.log('Inicializando face-api...');

    // Tiny Face Detector, Face Landmark 68, and Face Recognition Nets
    const MODEL_URL = 'https://cdn.jsdelivr.net/npm/@vladmandic/face-api/model/';
    console.log('Carregando modelos face-api do CDN...');
    await Promise.all([
      faceapi.nets.ssdMobilenetv1.loadFromUri(MODEL_URL),
      faceapi.nets.faceLandmark68Net.loadFromUri(MODEL_URL),
      faceapi.nets.faceRecognitionNet.loadFromUri(MODEL_URL)
    ]);
    console.log('Modelos carregados com sucesso!');

    // 2. Fetch students and their face descriptors from DB
    console.log('Buscando alunos do banco de dados...');
    const { rows: students } = await pool.query('SELECT id, nome, face_descriptor FROM alunos WHERE face_descriptor IS NOT NULL');
    console.log(`Encontrados ${students.length} alunos com biometria no banco.`);

    // 3. Read downloaded photos from disk
    const photosDir = path.join(__dirname, 'photos');
    const photoFiles = fs.readdirSync(photosDir).filter(f => f.endsWith('.webp'));
    console.log(`Encontradas ${photoFiles.length} fotos webp locais.`);

    const results = [];

    // 4. Process each photo, get its descriptor, and find best match
    for (const file of photoFiles) {
      const filePath = path.join(photosDir, file);
      console.log(`Processando ${file}...`);

      // Use sharp to convert webp to raw RGB buffer for face-api tensor
      const image = sharp(filePath);
      const metadata = await image.metadata();
      const { data, info } = await image
        .raw()
        .toBuffer({ resolveWithObject: true });

      // Create tensor from raw pixels
      const tensor = faceapi.tf.tensor3d(
        new Uint8Array(data),
        [info.height, info.width, 3],
        'int32'
      );

      // Detect face and extract descriptor
      const detection = await faceapi.detectSingleFace(tensor)
        .withFaceLandmarks()
        .withFaceDescriptor();

      tensor.dispose();

      if (!detection) {
        console.warn(`Nenhum rosto detectado na foto ${file}`);
        continue;
      }

      const imgDescriptor = detection.descriptor;

      // Compare with all students using Euclidean distance
      let bestMatch = null;
      let minDistance = Infinity;

      for (const s of students) {
        const dbDescriptorStr = typeof s.face_descriptor === 'string'
          ? s.face_descriptor
          : JSON.stringify(s.face_descriptor);

        const dbDescriptor = new Float32Array(JSON.parse(dbDescriptorStr));
        const distance = faceapi.euclideanDistance(imgDescriptor, dbDescriptor);

        if (distance < minDistance) {
          minDistance = distance;
          bestMatch = s;
        }
      }

      console.log(`Foto: ${file} | Melhor Match: ${bestMatch?.nome} | Distância: ${minDistance.toFixed(4)}`);
      results.push({
        file,
        studentId: bestMatch?.id,
        studentName: bestMatch?.nome,
        distance: minDistance
      });
    }

    console.log('\n--- RESULTADO DE PROJEÇÃO DE CORRELAÇÃO DE BIOMETRIA ---');
    results.forEach(r => {
      console.log(`Foto: ${r.file} -> Aluno: ${r.studentName} (ID: ${r.studentId}) | Distância: ${r.distance.toFixed(4)}`);
    });

  } catch (err) {
    console.error('Erro na execução:', err);
  } finally {
    await pool.end();
  }
}

run();
