<?php
/**
 * MalwareSignaturesTable — standalone class file.
 *
 * @package UltraguardPro\modules\antivirus\db
 */

namespace UltraguardPro\modules\antivirus\db;

use UltraguardPro\db\BaseTable;
use UltraguardPro\core\DataCodec;

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

// MalwareSignaturesTable
class MalwareSignaturesTable extends BaseTable {

    protected $table_name  = 'ultraguard_malware_signatures';
    protected $cache_group = 'ultraguard_malware_signatures';

    /**
     * @return array<string,mixed>
     */
    public function get_defaults(): array {
        return [
            'id'             => 0,
            'signature_hash' => '',
            'name'           => '',
            'type'           => 'hash',
            'pattern'        => null,
            'threat_level'   => 'medium',
            'is_active'      => 1,
            'source'         => null,
            'hits_count'     => 0,
            'created_at'     => '',
            'updated_at'     => '',
        ];
    }

    /**
     * @param  array<string,mixed>|false $data
     * @return array<string,mixed>|false
     */
    protected function validate_data( $data ) {
        if ( empty( $data['signature_hash'] ) || empty( $data['name'] ) ) {
            return false;
        }
        $valid_types = [ 'hash', 'pattern', 'heuristic', 'regex' ];
        if ( isset( $data['type'] ) && ! in_array( $data['type'], $valid_types, true ) ) {
            return false;
        }
        return $data;
    }

    /**
     * @param  array<string,mixed> $data
     * @return array<string,mixed>
     */
    protected function sanitize_data( $data ): array {
        $out = [];
        foreach ( $data as $k => $v ) {
            $out[ $k ] = match ( $k ) {
                // Regex patterns must NOT be passed through sanitize_textarea_field():
                // that function calls wp_strip_all_tags() which destroys patterns
                // containing HTML-like tokens (e.g. /<script[\s>]/i becomes /]/i).
                // Use sanitize_regex_pattern() which only removes null bytes and
                // validates UTF-8 — safe for wpdb->prepare() via %s.
                'pattern'    => is_null( $v ) ? null : self::sanitize_regex_pattern( (string) $v ),
                'hits_count' => absint( $v ),
                'is_active'  => (int) (bool) $v,
                default      => is_string( $v ) ? sanitize_text_field( $v ) : $v,
            };
        }
        return $out;
    }

    /** @deprecated Use BaseTable::sanitize_regex_pattern() directly. */
    public static function sanitize_regex_pattern( string $pattern ): string {
        return parent::sanitize_regex_pattern( $pattern );
    }

    // ── Domain methods ─────────────────────────────────────────────────────────

    /**
     * Retrieve all active signatures, ordered by threat level (critical first).
     *
     * @param  int $limit
     * @return array<int,array<string,mixed>>
     */
    public function get_active_signatures( int $limit = 5000 ): array {
        return $this->get_by( [ 'is_active' => 1 ], $limit, 'threat_level', 'DESC' );
    }

    /**
     * Find a signature by its hash value.
     *
     * @param  string $hash  MD5 or sentinel hash string.
     * @return array<string,mixed>|null  Signature row or null if not found.
     */
    public function find_by_hash( string $hash ): ?array {
        $sig = $this->get_by_field( 'signature_hash', sanitize_text_field( $hash ) );
        return ( $sig && ! empty( $sig['id'] ) ) ? $sig : null;
    }

    /**
     * Increment the hits counter for a matched signature.
     *
     * @param  int $id  Signature record ID.
     * @return bool
     */
    public function increment_hits( int $id ): bool {
        return $this->increment_field( 'hits_count', [ 'id' => $id ] );
    }

    /**
     * Retrieve all signatures from a specific source.
     *
     * @param  string $source  Source label (e.g. 'ultraguard', 'community').
     * @return array<int,array<string,mixed>>
     */
    public function get_by_source( string $source ): array {
        return $this->get_by( [ 'source' => sanitize_text_field( $source ) ], 5000 );
    }

    // ── DataCodec integration ───────────────────────────────────────────────────

    /**
     * The 'pattern' column stores raw regex strings (e.g. /<script[\s>]/i) that
     * are destroyed by sanitize_text_field() / wp_strip_all_tags().
     * DataCodec wraps the value in a Base64 envelope before DatabaseCrud sees it
     * and unwraps it transparently on every read.
     *
     * @return string[]
     */
    protected function get_codec_fields(): array {
        return [ 'pattern' ];
    }

    /**
     * @return string[]
     */
    protected function get_searchable_fields(): array {
        return [ 'signature_hash', 'name', 'type', 'source' ];
    }
}

// VulnerabilityScansTable
// =============================================================================
