<?php
/**
 * VmpFence File Changes Sync Module
 *
 * Syncs records from wp_vmpfence_file_changes to the backend
 * via POST /api/v1/scanner/file-changes/batch (payload key: 'changes')
 *
 * @package    VMPFence
 * @subpackage Includes\Sync
 * @since      2.2.4
 */

if (!defined('ABSPATH')) {
    exit;
}

class VmpFence_File_Changes_Sync extends VmpFence_Base_Sync {

    /**
     * Records per API call
     * @var int
     */
    protected $batch_size = 50;

    /**
     * Constructor
     *
     * @since 2.2.4
     */
    public function __construct() {
        global $wpdb;
        $this->table_name = $wpdb->prefix . 'vmpfence_file_changes';
        parent::__construct();
    }

    /**
     * Get the API client method name for this sync module.
     *
     * @since 2.2.4
     * @return string
     */
    protected function get_endpoint_method(): string {
        return 'sync_file_changes_batch';
    }

    /**
     * Transform a database row into the API payload format.
     *
     * DB Audit (Feb 16, 2026):
     * - Server expects `new_hash`, NOT `file_hash`
     * - `file_type`, `detected_by`, `severity` are NOT NULL on server — included with defaults
     * - `timestamp` is double(17,6) Unix timestamp — converted via date()
     *
     * Column Audit (Feb 15, 2026 — Bugfix):
     * - No `file_type` column — derive from file extension
     * - No `severity` column — derive from action type
     *
     * @since 2.2.4
     * @param array $row Database row
     * @return array Transformed record
     */
    protected function transform_record(array $row): array {
        $file_path = $row['file'] ?? '';
        $action = $row['action'] ?? 'modified';

        return array(
            'plugin_event_id' => (int) $row['id'],
            'file_path'       => $file_path,
            'file_type'       => self::derive_file_type($file_path),
            'change_type'     => $action,
            'new_hash'        => $row['md5'] ?? '',
            'detected_by'     => 'scanner',
            'severity'        => ($action === 'deleted' || $action === 'added') ? 'medium' : 'info',
            'detected_at'     => isset($row['timestamp']) ? gmdate('Y-m-d\TH:i:s\Z', (int) $row['timestamp']) : current_time('c'),
        );
    }

    /**
     * Derive file type from file path extension.
     *
     * @since 2.2.4
     * @param string $file_path File path
     * @return string File type category
     */
    private static function derive_file_type(string $file_path): string {
        $ext = strtolower(pathinfo($file_path, PATHINFO_EXTENSION));

        $type_map = array(
            'php' => 'php', 'phtml' => 'php', 'php5' => 'php',
            'js' => 'javascript', 'mjs' => 'javascript',
            'css' => 'stylesheet',
            'html' => 'html', 'htm' => 'html',
            'json' => 'config', 'xml' => 'config', 'ini' => 'config', 'yml' => 'config', 'yaml' => 'config',
            'png' => 'media', 'jpg' => 'media', 'jpeg' => 'media', 'gif' => 'media', 'svg' => 'media', 'webp' => 'media',
            'txt' => 'text', 'md' => 'text', 'log' => 'text',
        );

        return $type_map[$ext] ?? 'unknown';
    }
}
