<?php
/**
 * API de vérification de photo
 * POST /api/verify-photo
 * Compare la photo capturée avec la photo de référence du chauffeur
 * 5 méthodes combinées : histogramme RGB, histogramme de luminance,
 * SSIM, comparaison par blocs, détection de contours (edges)
 * L'image capturée est supprimée après comparaison
 */

require_once __DIR__ . '/../db.php';
require_once __DIR__ . '/../auth.php';

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    echo json_encode(['success' => false, 'message' => 'Méthode non autorisée']);
    exit;
}

$payload = requireAuth();

$input = json_decode(file_get_contents('php://input'), true);

if (!isset($input['employee_id']) || !isset($input['image_base64'])) {
    http_response_code(400);
    echo json_encode(['success' => false, 'message' => 'employee_id et image_base64 requis']);
    exit;
}

try {
    $db = getDB();

    $stmt = $db->prepare("
        SELECT id, nom, prenom, nomprenom, photo_reference
        FROM employees
        WHERE id = :id AND actif = 1
    ");
    $stmt->execute(['id' => $input['employee_id']]);
    $employee = $stmt->fetch();

    if (!$employee) {
        http_response_code(404);
        echo json_encode(['success' => false, 'message' => 'Employé non trouvé']);
        exit;
    }

    // Décoder l'image capturée (en mémoire, pas sur disque)
    $imageData = base64_decode($input['image_base64']);
    $captureImg = @imagecreatefromstring($imageData);

    if (!$captureImg) {
        http_response_code(400);
        echo json_encode(['success' => false, 'message' => 'Image invalide']);
        exit;
    }

    $photoRef = $employee['photo_reference'];
    $photoExists = false;
    $photoRefUrl = null;
    $similarity = 0;
    $matchResult = false;
    $scores = [];

    if (!empty($photoRef)) {
        $refPath = __DIR__ . '/../' . $photoRef;
        if (file_exists($refPath)) {
            $photoExists = true;
            $photoRefUrl = $photoRef;

            $refImg = loadImageFromFile($refPath);

            if ($refImg) {
                // === MÉTHODE 1 : Histogramme RGB ===
                $scores['hist_rgb'] = compareHistogramRGB($captureImg, $refImg);

                // === MÉTHODE 2 : Histogramme de luminance ===
                $scores['hist_lum'] = compareHistogramLuminance($captureImg, $refImg);

                // === MÉTHODE 3 : SSIM (Similarité structurelle) ===
                $scores['ssim'] = compareSSIM($captureImg, $refImg);

                // === MÉTHODE 4 : Comparaison par blocs ===
                $scores['blocks'] = compareBlocks($captureImg, $refImg);

                // === MÉTHODE 5 : Détection de contours (edges) ===
                $scores['edges'] = compareEdges($captureImg, $refImg);

                // Combinaison pondérée des 5 méthodes
                $similarity = round(
                    $scores['hist_rgb'] * 0.15 +
                    $scores['hist_lum'] * 0.15 +
                    $scores['ssim']     * 0.30 +
                    $scores['blocks']   * 0.25 +
                    $scores['edges']    * 0.15,
                    2
                );

                // Seuil de correspondance : 55%
                $matchResult = $similarity >= 55;

                imagedestroy($refImg);
            }
        }
    }

    // Supprimer l'image capturée après comparaison
    imagedestroy($captureImg);

    echo json_encode([
        'success' => true,
        'message' => $matchResult
            ? 'Photo correspondante (' . $similarity . '%)'
            : ($photoExists
                ? 'Photo non correspondante (' . $similarity . '%)'
                : 'Aucune photo de référence enregistrée'),
        'employee' => [
            'id' => (int)$employee['id'],
            'nomprenom' => $employee['nomprenom'] ?? ($employee['nom'] . ' ' . $employee['prenom']),
            'photo_reference' => $photoRefUrl,
            'photo_reference_exists' => $photoExists
        ],
        'photo_match' => $matchResult,
        'similarity' => $similarity,
        'detail_scores' => $scores
    ]);

} catch (Exception $e) {
    error_log("Erreur verify-photo: " . $e->getMessage());
    http_response_code(500);
    echo json_encode(['success' => false, 'message' => 'Erreur serveur: ' . $e->getMessage()]);
}

// ============================================================
// FONCTIONS DE COMPARAISON
// ============================================================

function loadImageFromFile($path) {
    $info = @getimagesize($path);
    if (!$info) return null;
    switch ($info[2]) {
        case IMAGETYPE_JPEG: return @imagecreatefromjpeg($path);
        case IMAGETYPE_PNG:  return @imagecreatefrompng($path);
        case IMAGETYPE_GIF:  return @imagecreatefromgif($path);
        default: return null;
    }
}

/**
 * Méthode 1 : Histogramme RGB
 * Compare la distribution des couleurs R, G, B
 */
function compareHistogramRGB($img1, $img2) {
    $size = 128;
    $r1 = imagecreatetruecolor($size, $size);
    $r2 = imagecreatetruecolor($size, $size);
    imagecopyresampled($r1, $img1, 0, 0, 0, 0, $size, $size, imagesx($img1), imagesy($img1));
    imagecopyresampled($r2, $img2, 0, 0, 0, 0, $size, $size, imagesx($img2), imagesy($img2));

    // Histogrammes à 16 bins par canal
    $bins = 16;
    $h1 = array_fill(0, $bins * 3, 0);
    $h2 = array_fill(0, $bins * 3, 0);

    for ($y = 0; $y < $size; $y++) {
        for ($x = 0; $x < $size; $x++) {
            $c1 = imagecolorat($r1, $x, $y);
            $c2 = imagecolorat($r2, $x, $y);

            $h1[(($c1 >> 16) & 0xFF) >> 4]++;
            $h1[$bins + (($c1 >> 8) & 0xFF) >> 4]++;
            $h1[$bins * 2 + ($c1 & 0xFF) >> 4]++;

            $h2[(($c2 >> 16) & 0xFF) >> 4]++;
            $h2[$bins + (($c2 >> 8) & 0xFF) >> 4]++;
            $h2[$bins * 2 + ($c2 & 0xFF) >> 4]++;
        }
    }

    // Normaliser
    $total = $size * $size;
    for ($i = 0; $i < $bins * 3; $i++) {
        $h1[$i] /= $total;
        $h2[$i] /= $total;
    }

    // Bhattacharyya distance
    $bc = 0;
    for ($i = 0; $i < $bins * 3; $i++) {
        $bc += sqrt($h1[$i] * $h2[$i]);
    }
    $similarity = (1 - sqrt(1 - $bc)) * 100;

    imagedestroy($r1);
    imagedestroy($r2);

    return max(0, min(100, round($similarity, 2)));
}

/**
 * Méthode 2 : Histogramme de luminance
 * Compare la distribution des niveaux de gris
 */
function compareHistogramLuminance($img1, $img2) {
    $size = 128;
    $r1 = imagecreatetruecolor($size, $size);
    $r2 = imagecreatetruecolor($size, $size);
    imagecopyresampled($r1, $img1, 0, 0, 0, 0, $size, $size, imagesx($img1), imagesy($img1));
    imagecopyresampled($r2, $img2, 0, 0, 0, 0, $size, $size, imagesx($img2), imagesy($img2));

    $bins = 32;
    $h1 = array_fill(0, $bins, 0);
    $h2 = array_fill(0, $bins, 0);

    for ($y = 0; $y < $size; $y++) {
        for ($x = 0; $x < $size; $x++) {
            $c1 = imagecolorat($r1, $x, $y);
            $c2 = imagecolorat($r2, $x, $y);

            $lum1 = (($c1 >> 16) & 0xFF) * 0.299 + (($c1 >> 8) & 0xFF) * 0.587 + ($c1 & 0xFF) * 0.114;
            $lum2 = (($c2 >> 16) & 0xFF) * 0.299 + (($c2 >> 8) & 0xFF) * 0.587 + ($c2 & 0xFF) * 0.114;

            $h1[(int)($lum1 / 8)]++;
            $h2[(int)($lum2 / 8)]++;
        }
    }

    $total = $size * $size;
    $diff = 0;
    for ($i = 0; $i < $bins; $i++) {
        $diff += abs($h1[$i] / $total - $h2[$i] / $total);
    }

    $similarity = max(0, (1 - $diff / 2) * 100);

    imagedestroy($r1);
    imagedestroy($r2);

    return round($similarity, 2);
}

/**
 * Méthode 3 : SSIM (Structural Similarity Index)
 * Compare luminance, contraste et structure
 */
function compareSSIM($img1, $img2) {
    $size = 64;
    $r1 = imagecreatetruecolor($size, $size);
    $r2 = imagecreatetruecolor($size, $size);
    imagecopyresampled($r1, $img1, 0, 0, 0, 0, $size, $size, imagesx($img1), imagesy($img1));
    imagecopyresampled($r2, $img2, 0, 0, 0, 0, $size, $size, imagesx($img2), imagesy($img2));

    // Convertir en niveaux de gris
    $g1 = []; $g2 = [];
    for ($y = 0; $y < $size; $y++) {
        for ($x = 0; $x < $size; $x++) {
            $c1 = imagecolorat($r1, $x, $y);
            $c2 = imagecolorat($r2, $x, $y);
            $g1[] = (($c1 >> 16) & 0xFF) * 0.299 + (($c1 >> 8) & 0xFF) * 0.587 + ($c1 & 0xFF) * 0.114;
            $g2[] = (($c2 >> 16) & 0xFF) * 0.299 + (($c2 >> 8) & 0xFF) * 0.587 + ($c2 & 0xFF) * 0.114;
        }
    }

    $n = count($g1);
    $mean1 = array_sum($g1) / $n;
    $mean2 = array_sum($g2) / $n;

    $var1 = 0; $var2 = 0; $cov = 0;
    for ($i = 0; $i < $n; $i++) {
        $d1 = $g1[$i] - $mean1;
        $d2 = $g2[$i] - $mean2;
        $var1 += $d1 * $d1;
        $var2 += $d2 * $d2;
        $cov  += $d1 * $d2;
    }
    $var1 /= $n;
    $var2 /= $n;
    $cov  /= $n;

    $c1 = pow(0.01 * 255, 2);
    $c2 = pow(0.03 * 255, 2);
    $c3 = $c2 / 2;

    $luminance = (2 * $mean1 * $mean2 + $c1) / ($mean1 * $mean1 + $mean2 * $mean2 + $c1);
    $contrast  = (2 * sqrt($var1) * sqrt($var2) + $c2) / ($var1 + $var2 + $c2);
    $structure = ($cov + $c3) / (sqrt($var1) * sqrt($var2) + $c3);

    $ssim = $luminance * $contrast * $structure;
    $similarity = max(0, min(100, $ssim * 100));

    imagedestroy($r1);
    imagedestroy($r2);

    return round($similarity, 2);
}

/**
 * Méthode 4 : Comparaison par blocs
 * Divise l'image en grille 4x4 et compare chaque bloc
 */
function compareBlocks($img1, $img2) {
    $size = 128;
    $r1 = imagecreatetruecolor($size, $size);
    $r2 = imagecreatetruecolor($size, $size);
    imagecopyresampled($r1, $img1, 0, 0, 0, 0, $size, $size, imagesx($img1), imagesy($img1));
    imagecopyresampled($r2, $img2, 0, 0, 0, 0, $size, $size, imagesx($img2), imagesy($img2));

    $gridSize = 4;
    $blockSize = $size / $gridSize;
    $totalMatch = 0;

    for ($by = 0; $by < $gridSize; $by++) {
        for ($bx = 0; $bx < $gridSize; $bx++) {
            $sum1 = [0, 0, 0];
            $sum2 = [0, 0, 0];
            $count = $blockSize * $blockSize;

            for ($y = $by * $blockSize; $y < ($by + 1) * $blockSize; $y++) {
                for ($x = $bx * $blockSize; $x < ($bx + 1) * $blockSize; $x++) {
                    $c1 = imagecolorat($r1, $x, $y);
                    $c2 = imagecolorat($r2, $x, $y);

                    $sum1[0] += ($c1 >> 16) & 0xFF;
                    $sum1[1] += ($c1 >> 8) & 0xFF;
                    $sum1[2] += $c1 & 0xFF;

                    $sum2[0] += ($c2 >> 16) & 0xFF;
                    $sum2[1] += ($c2 >> 8) & 0xFF;
                    $sum2[2] += $c2 & 0xFF;
                }
            }

            $diff = 0;
            for ($c = 0; $c < 3; $c++) {
                $avg1 = $sum1[$c] / $count;
                $avg2 = $sum2[$c] / $count;
                $diff += abs($avg1 - $avg2) / 255;
            }
            $totalMatch += max(0, 1 - $diff / 3);
        }
    }

    $similarity = ($totalMatch / ($gridSize * $gridSize)) * 100;

    imagedestroy($r1);
    imagedestroy($r2);

    return round($similarity, 2);
}

/**
 * Méthode 5 : Détection de contours (Sobel edge detection)
 * Compare les structures/formes des images via les contours
 */
function compareEdges($img1, $img2) {
    $size = 64;
    $r1 = imagecreatetruecolor($size, $size);
    $r2 = imagecreatetruecolor($size, $size);
    imagecopyresampled($r1, $img1, 0, 0, 0, 0, $size, $size, imagesx($img1), imagesy($img1));
    imagecopyresampled($r2, $img2, 0, 0, 0, 0, $size, $size, imagesx($img2), imagesy($img2));

    // Convertir en niveaux de gris
    $g1 = []; $g2 = [];
    for ($y = 0; $y < $size; $y++) {
        for ($x = 0; $x < $size; $x++) {
            $c1 = imagecolorat($r1, $x, $y);
            $c2 = imagecolorat($r2, $x, $y);
            $g1[$y][$x] = (($c1 >> 16) & 0xFF) * 0.299 + (($c1 >> 8) & 0xFF) * 0.587 + ($c1 & 0xFF) * 0.114;
            $g2[$y][$x] = (($c2 >> 16) & 0xFF) * 0.299 + (($c2 >> 8) & 0xFF) * 0.587 + ($c2 & 0xFF) * 0.114;
        }
    }

    // Sobel kernels
    $sobX = [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]];
    $sobY = [[-1, -2, -1], [0, 0, 0], [1, 2, 1]];

    $edges1 = []; $edges2 = [];
    $edgeCount1 = 0; $edgeCount2 = 0;

    for ($y = 1; $y < $size - 1; $y++) {
        for ($x = 1; $x < $size - 1; $x++) {
            $gx1 = 0; $gy1 = 0;
            $gx2 = 0; $gy2 = 0;

            for ($ky = -1; $ky <= 1; $ky++) {
                for ($kx = -1; $kx <= 1; $kx++) {
                    $gx1 += $g1[$y + $ky][$x + $kx] * $sobX[$ky + 1][$kx + 1];
                    $gy1 += $g1[$y + $ky][$x + $kx] * $sobY[$ky + 1][$kx + 1];
                    $gx2 += $g2[$y + $ky][$x + $kx] * $sobX[$ky + 1][$kx + 1];
                    $gy2 += $g2[$y + $ky][$x + $kx] * $sobY[$ky + 1][$kx + 1];
                }
            }

            $mag1 = sqrt($gx1 * $gx1 + $gy1 * $gy1);
            $mag2 = sqrt($gx2 * $gx2 + $gy2 * $gy2);

            $edges1[$y][$x] = $mag1;
            $edges2[$y][$x] = $mag2;

            if ($mag1 > 50) $edgeCount1++;
            if ($mag2 > 50) $edgeCount2++;
        }
    }

    // Comparer les patterns de contours
    $match = 0;
    $total = 0;
    for ($y = 1; $y < $size - 1; $y++) {
        for ($x = 1; $x < $size - 1; $x++) {
            $e1 = $edges1[$y][$x] ?? 0;
            $e2 = $edges2[$y][$x] ?? 0;

            // Les deux ont un contour ou les deux n'en ont pas
            $isEdge1 = $e1 > 50;
            $isEdge2 = $e2 > 50;

            if ($isEdge1 === $isEdge2) {
                $match++;
            }

            // Comparer l'intensité des contours
            if ($isEdge1 && $isEdge2) {
                $intensityDiff = abs($e1 - $e2) / max($e1, $e2, 1);
                $match += max(0, 1 - $intensityDiff);
                $total++;
            }
            $total++;
        }
    }

    $similarity = ($match / max($total, 1)) * 100;

    imagedestroy($r1);
    imagedestroy($r2);

    return round($similarity, 2);
}
