<?php
require_once 'db_config.php';
require_once 'security.php';

header('Content-Type: application/json; charset=utf-8');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST');
header('Access-Control-Allow-Headers: Content-Type, Authorization');

// Valider le token et appliquer rate limiting/whitelist
$auth = new ApiSecurity();
$tokenData = $auth->requireAuth(true); // true = token obligatoire

// Rendre les données du token disponibles pour les actions
$authUser = $tokenData['sub'];     // code_utilisateur
$authRole = $tokenData['role'];     // rôle
$authSite = $tokenData['site'];     // SiteID

// Headers de monitoring de sécurité
header('X-RateLimit-Remaining: ' . ($auth->checkRateLimit()['remaining'] ?? 'unknown'));

// Désactiver complètement l'affichage des erreurs en production
error_reporting(0);
ini_set('display_errors', 0);
ini_set('log_errors', 1);
ini_set('error_log', __DIR__ . '/versement_errors.log');

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

// ==========================================
// VALIDATION ET NETTOYAGE DES ENTRÉES
// ==========================================

/**
 * Nettoie et valide une chaîne d'entrée
 */
function sanitizeInput($data) {
    if (!isset($data) || is_null($data)) return '';
    $data = trim($data);
    // Supprimer les caractères de contrôle ASCII (sauf tab, newline, return)
    $data = preg_replace('/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/', '', $data);
    return $data;
}

/**
 * Valide que les paramètres requis ne sont pas vides
 */
function validateRequired($params, $keys) {
    $missing = [];
    foreach ($keys as $key) {
        if (!isset($params[$key]) || empty(trim((string)$params[$key]))) {
            $missing[] = $key;
        }
    }
    return count($missing) > 0 ? $missing : null;
}

/**
 * Vérifie que la valeur est une date valide au format YYYY-MM-DD
 */
function isValidDate($date, $format = 'Y-m-d') {
    $d = DateTime::createFromFormat($format, $date);
    return $d && $d->format($format) === $date;
}

// Récupération et nettoyage de tous les paramètres POST
$input = [];
foreach ($_POST as $key => $value) {
    $input[$key] = sanitizeInput($value);
}

$action = $input['action'] ?? '';

// Vérifier que l'action n'est pas dans la liste noire
$blockedActions = ['drop', 'delete', 'truncate', 'alter', 'create', 'exec', 'eval'];
foreach ($blockedActions as $blocked) {
    if (stripos($action, $blocked) !== false) {
        http_response_code(403);
        echo json_encode(['success' => false, 'message' => 'Action non autorisée']);
        exit;
    }
}

$conn = getConnectionPointage();
if (!$conn) {
    http_response_code(500);
    echo json_encode(['success' => false, 'message' => 'Erreur de connexion à la base de données']);
    exit;
}

// ============ ACTION: get_site_name ============
if ($action == 'get_site_name') {
    $siteID = $input['siteID'] ?? '';
    
    $missing = validateRequired($_POST, ['siteID']);
    if ($missing) {
        echo json_encode(['success' => false, 'message' => 'SiteID requis']);
        $conn->close();
        exit;
    }
    
    // Valider que SiteID est alphanumérique
    if (!preg_match('/^[a-zA-Z0-9_-]+$/', $siteID)) {
        echo json_encode(['success' => false, 'message' => 'SiteID invalide']);
        $conn->close();
        exit;
    }
    
    $sql = "SELECT Nom_Site FROM Sites WHERE SiteID = ? LIMIT 1";
    $stmt = $conn->prepare($sql);
    if ($stmt) {
        $stmt->bind_param("s", $siteID);
        $stmt->execute();
        $result = $stmt->get_result();
        $row = $result->fetch_assoc();
        $stmt->close();
        
        if ($row) {
            echo json_encode([
                'success' => true,
                'data' => ['nom_site' => $row['Nom_Site']]
            ]);
        } else {
            echo json_encode([
                'success' => false,
                'message' => 'Site non trouvé'
            ]);
        }
    } else {
        echo json_encode(['success' => false, 'message' => 'Erreur de requête']);
    }
    $conn->close();
    exit;
}

// ============ ACTION: get_tarifs ============
if ($action == 'get_tarifs') {
    $sql = "SELECT id_article, ttc FROM tarifs_circuits ORDER BY type ASC";
    $result = $conn->query($sql);
    
    $tarifs = array();
    if ($result && $result->num_rows > 0) {
        while ($row = $result->fetch_assoc()) {
            $tarifs[] = $row;
        }
    }
    
    echo json_encode([
        'success' => true,
        'data' => $tarifs
    ]);
    $conn->close();
    exit;
}

// ============ ACTION: check_doublon ============
if ($action == 'check_doublon') {
    $missing = validateRequired($_POST, ['operateur', 'types', 'periode', 'siteID']);
    if ($missing) {
        echo json_encode(['success' => false, 'message' => 'Paramètres manquants: ' . implode(', ', $missing)]);
        $conn->close();
        exit;
    }
    
    $operateur = $input['operateur'] ?? '';
    $types = $input['types'] ?? '';
    $periode = $input['periode'] ?? '';
    $siteID = $input['siteID'] ?? '';
    
    // Valider le format de la période (YYYY-MM)
    if (!preg_match('/^\d{4}-\d{2}$/', $periode)) {
        echo json_encode(['success' => false, 'message' => 'Format période invalide']);
        $conn->close();
        exit;
    }
    
    $typeArray = explode(',', $types);
    $alreadyExists = array();
    $monthStart = $periode . '-01';
    
    foreach ($typeArray as $type) {
        $type = trim($type);
        // Valider le type de véhicule
        if (empty($type) || strlen($type) > 50) continue;
        
        $sql = "SELECT COUNT(*) as nb FROM bons_vers_circuits 
                WHERE operateur = ? AND type_vehicule = ? AND periode_p = ? AND date_vers >= ?";
        
        $stmt = $conn->prepare($sql);
        if ($stmt) {
            $stmt->bind_param("ssss", $operateur, $type, $periode, $monthStart);
            $stmt->execute();
            $result = $stmt->get_result();
            $row = $result->fetch_assoc();
            $stmt->close();
            
            if ($row && $row['nb'] > 0) {
                $alreadyExists[] = $type;
            }
        }
    }
    
    if (count($alreadyExists) > 0) {
        echo json_encode([
            'success' => false,
            'message' => 'Doublon',
            'error_type' => 'DOUBLON_VERSEMENT',
            'error_detail' => implode(',', $alreadyExists)
        ]);
    } else {
        echo json_encode(['success' => true, 'message' => 'Aucun doublon']);
    }
    $conn->close();
    exit;
}

// ============ ACTION: generer_bvr ============
if ($action == 'generer_bvr') {
    $missing = validateRequired($_POST, ['siteID']);
    if ($missing) {
        echo json_encode(['success' => false, 'message' => 'SiteID requis']);
        $conn->close();
        exit;
    }
    
    $siteID = $input['siteID'] ?? '';
    
    // Valider SiteID
    if (!preg_match('/^[a-zA-Z0-9_-]+$/', $siteID)) {
        echo json_encode(['success' => false, 'message' => 'SiteID invalide']);
        $conn->close();
        exit;
    }
    
    // Nettoyer siteID: enlever prefixe "ST" si présent
    $siteID_clean = $siteID;
    if (strlen($siteID) > 2 && strtoupper(substr($siteID, 0, 2)) == 'ST') {
        $siteID_clean = substr($siteID, 2);
    }
    
    // S'assurer que le nettoyage donne un résultat numérique valide
    if (!ctype_digit($siteID_clean) && !is_numeric($siteID_clean)) {
        echo json_encode(['success' => false, 'message' => 'SiteID invalide après traitement']);
        $conn->close();
        exit;
    }
    
    // Récupérer le dernier numéro séquentiel
    $prefix = 'BVR-ST' . str_pad($siteID_clean, 2, '0', STR_PAD_LEFT) . '-';
    $sql = "SELECT num_vers FROM bons_vers_circuits WHERE num_vers LIKE ? ORDER BY id DESC LIMIT 1";
    $likePrefix = $prefix . '%';
    
    $stmt = $conn->prepare($sql);
    $seq = 1;
    if ($stmt) {
        $stmt->bind_param("s", $likePrefix);
        $stmt->execute();
        $result = $stmt->get_result();
        $row = $result->fetch_assoc();
        $stmt->close();
        
        if ($row && isset($row['num_vers'])) {
            $lastNum = $row['num_vers'];
            $parts = explode('-', $lastNum);
            if (isset($parts[2]) && is_numeric($parts[2])) {
                $seq = (int)$parts[2] + 1;
            }
        }
    }
    
    $bvr = $prefix . str_pad($seq, 6, '0', STR_PAD_LEFT);
    
    echo json_encode([
        'success' => true,
        'data' => ['num_vers' => $bvr]
    ]);
    $conn->close();
    exit;
}

// ============ ACTION: get_matricule_for_periode ============
if ($action == 'get_matricule_for_periode') {
    $missing = validateRequired($_POST, ['operateur_id', 'type', 'periode', 'siteID']);
    if ($missing) {
        echo json_encode(['success' => false, 'message' => 'Paramètres manquants']);
        $conn->close();
        exit;
    }
    
    $operateur_id = $input['operateur_id'] ?? '';
    $id_type_vehicule = $input['type'] ?? '';
    $periode = $input['periode'] ?? '';
    $siteID = $input['siteID'] ?? '';
    
    // Valider le format de la période
    if (!preg_match('/^\d{4}-\d{2}$/', $periode)) {
        echo json_encode(['success' => false, 'message' => 'Format période invalide']);
        $conn->close();
        exit;
    }
    
    $monthStart = $periode . '-01';
    
    // Jointure correcte : checkins_circuits.vehicule_id = vehicules_circuits.id
    $sql = "SELECT c.notes, c.checkin_date
            FROM checkins_circuits c
            INNER JOIN vehicules_circuits v ON c.vehicule_id = v.id
            WHERE v.id_operateur = ? AND v.id_type_vehicule = ? AND v.SiteID = ?
              AND c.checkin_date >= ? AND c.checkin_date < ?
            ORDER BY c.checkin_date DESC LIMIT 1";
    
    $stmt = $conn->prepare($sql);
    if (!$stmt) {
        echo json_encode(['success' => false, 'message' => 'Erreur de requête']);
        $conn->close();
        exit;
    }
    $stmt->bind_param("sssss", $operateur_id, $id_type_vehicule, $siteID, $monthStart, $monthStart);
    $stmt->execute();
    $result = $stmt->get_result();
    $row = $result->fetch_assoc();
    $stmt->close();
    
    if ($row) {
        echo json_encode([
            'success' => true,
            'data' => [
                'matricule' => $row['notes'] ?: '',
                'checkin_date' => $row['checkin_date']
            ]
        ]);
    } else {
        echo json_encode([
            'success' => false,
            'message' => 'Aucun pointage trouvé pour cette période'
        ]);
    }
    $conn->close();
    exit;
}

// ============ ACTION: save_versement ============
if ($action == 'save_versement') {
    $required = ['num_vers', 'date_vers', 'periode_p', 'type_vehicule'];
    $missing = validateRequired($_POST, $required);
    
    if ($missing) {
        echo json_encode(['success' => false, 'message' => 'Paramètres requis manquants: ' . implode(', ', $missing)]);
        $conn->close();
        exit;
    }
    
    $num_vers = $input['num_vers'] ?? '';
    $date_vers = $input['date_vers'] ?? '';
    $periode_p = $input['periode_p'] ?? '';
    $operateur = $input['operateur'] ?? '';
    $operateur_id = $input['operateur_id'] ?? '';
    $type_vehicule = $input['type_vehicule'] ?? '';
    $matricule = $input['matricule'] ?? '';
    $mt_ttc = isset($_POST['mt_ttc']) ? floatval($_POST['mt_ttc']) : 0;
    $creer_par = $input['creer_par'] ?? '';
    $obs = $input['obs'] ?? '';
    
    // Valider le format du numéro de versement
    if (!preg_match('/^[a-zA-Z0-9\-]+$/', $num_vers)) {
        echo json_encode(['success' => false, 'message' => 'Numéro de versement invalide']);
        $conn->close();
        exit;
    }
    
    // Valider le format de la date
    if (!isValidDate($date_vers)) {
        echo json_encode(['success' => false, 'message' => 'Format de date invalide (attendu: YYYY-MM-DD)']);
        $conn->close();
        exit;
    }
    
    // Valider le format de la période
    if (!preg_match('/^\d{4}-\d{2}$/', $periode_p)) {
        echo json_encode(['success' => false, 'message' => 'Format période invalide']);
        $conn->close();
        exit;
    }
    
    // Limiter la longueur des chaînes pour éviter les dépassements
    $type_vehicule = mb_substr($type_vehicule, 0, 100);
    $operateur = mb_substr($operateur, 0, 200);
    $matricule = mb_substr($matricule, 0, 50);
    $obs = mb_substr($obs, 0, 500);
    $creer_par = mb_substr($creer_par, 0, 100);
    
    // Valider le montant
    if ($mt_ttc < 0) {
        echo json_encode(['success' => false, 'message' => 'Montant invalide']);
        $conn->close();
        exit;
    }
    
    $date_creer = date('Y-m-d H:i:s');
    
    error_log("SAVE_VERSEMENT - Insert: num_vers=$num_vers date_vers=$date_vers periode_p=$periode_p operateur=$operateur type_vehicule='$type_vehicule' mt_ttc=$mt_ttc");
    
    $sql = "INSERT INTO bons_vers_circuits 
            (num_vers, date_vers, periode_p, operateur, type_vehicule, matricule, mt_ttc, obs, creer_par, date_creer)
            VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
    
    $stmt = $conn->prepare($sql);
    if (!$stmt) {
        error_log("SAVE_VERSEMENT PREPARE ERROR: " . $conn->error);
        echo json_encode(['success' => false, 'message' => 'Erreur interne']);
        $conn->close();
        exit;
    }
    $stmt->bind_param("ssssssdsss", 
        $num_vers, $date_vers, $periode_p, $operateur, $type_vehicule, 
        $matricule, $mt_ttc, $obs, $creer_par, $date_creer
    );
    
    if ($stmt->execute()) {
        $id = $stmt->insert_id;
        error_log("SAVE_VERSEMENT - OK id=$id");
        echo json_encode([
            'success' => true,
            'message' => 'Versement enregistré',
            'data' => ['id' => $id, 'num_vers' => $num_vers]
        ]);
    } else {
        error_log("SAVE_VERSEMENT EXECUTE ERROR: " . $stmt->error);
        echo json_encode([
            'success' => false,
            'message' => 'Erreur lors de l\'enregistrement'
        ]);
    }
    $stmt->close();
    $conn->close();
    exit;
}

 // ============ ACTION: get_versements ============
 if ($action == 'get_versements') {
     $missing = validateRequired($_POST, ['date_debut', 'date_fin', 'siteID']);
     if ($missing) {
         echo json_encode(['success' => false, 'message' => 'Paramètres manquants']);
         $conn->close();
         exit;
     }
     
     $date_debut = $input['date_debut'] ?? '';
     $date_fin = $input['date_fin'] ?? '';
     $guichetier = $input['guichetier'] ?? '';
     $siteID = $input['siteID'] ?? '';
     
     // Valider les dates
     if (!isValidDate($date_debut) || !isValidDate($date_fin)) {
         echo json_encode(['success' => false, 'message' => 'Format de date invalide']);
         $conn->close();
         exit;
     }
     
     // Valider SiteID
     if (!preg_match('/^[a-zA-Z0-9_-]+$/', $siteID)) {
         echo json_encode(['success' => false, 'message' => 'SiteID invalide']);
         $conn->close();
         exit;
     }
     
     // Construction de la requête avec paramètres préparés
     $sql = "SELECT * FROM bons_vers_circuits 
             WHERE date_vers >= ? AND date_vers <= ? AND SiteID = ?";
     
     $params = array($date_debut, $date_fin, $siteID);
     $types = "sss";
     
     if (!empty($guichetier) && strtoupper($guichetier) != "TOUS") {
         $sql .= " AND creer_par = ?";
         $types .= "s";
         $params[] = $guichetier;
     }
     
     $sql .= " ORDER BY date_vers DESC, id DESC";
     
     $stmt = $conn->prepare($sql);
     if (!$stmt) {
         echo json_encode(['success' => false, 'message' => 'Erreur de requête']);
         $conn->close();
         exit;
     }
     
     // Liaison dynamique des paramètres
     $stmt->bind_param($types, ...$params);
     $stmt->execute();
     $result = $stmt->get_result();
     
     $versements = array();
     while ($row = $result->fetch_assoc()) {
         $versements[] = $row;
     }
     
     echo json_encode([
         'success' => true,
         'data' => $versements
     ]);
     $stmt->close();
     $conn->close();
     exit;
 }

 echo json_encode(['success' => false, 'message' => 'Action inconnue']);
 $conn->close();
 ?>