<?php
/**
 * AbstractModuleSchema — Base class for all module-owned database schemas.
 *
 * Provides:
 *   • install()  — runs dbDelta on every schema returned by get_schemas().
 *   • uninstall() — drops all tables owned by this module.
 *   • Helper: table() — resolves the prefixed table name from the global $wpdb.
 *
 * Child classes implement:
 *   • get_schemas()   — return CREATE TABLE SQL strings keyed by full table name.
 *   • get_table_map() — return short_key → FQCN mapping.
 *   • get_module_id() — the module slug, e.g. 'antivirus'.
 *
 * @package UltraguardPro\modules\core
 */

namespace UltraguardPro\modules\core;

use UltraguardPro\contracts\ModuleSchemaInterface;

if ( ! defined( 'ABSPATH' ) ) { exit; }
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- Schema teardown uses validated internal table identifiers only.

abstract class AbstractModuleSchema implements ModuleSchemaInterface {

    // ── Abstract members ─────────────────────────────────────────────────────

    abstract public function get_schemas(): array;
    abstract public function get_table_map(): array;
    abstract public function get_module_id(): string;

    // ── Install / Uninstall ──────────────────────────────────────────────────

    /**
     * Run dbDelta on every CREATE TABLE statement this module owns.
     * Safe to call repeatedly — dbDelta only modifies what changed.
     */
    public function install(): void {
        if ( ! function_exists( 'dbDelta' ) ) {
            require_once ABSPATH . 'wp-admin/includes/upgrade.php';
        }

        foreach ( $this->get_schemas() as $table_name => $sql ) {
            if ( ! empty( $sql ) ) {
                dbDelta( $sql );
            }
        }

        do_action( 'ultraguard_pro/module_schema_installed', $this->get_module_id() );
    }

    /**
     * Drop all tables owned by this module.
     * Called during plugin uninstall — only when the admin confirms data removal.
     */
    public function uninstall(): void {
        global $wpdb;

        foreach ( array_keys( $this->get_schemas() ) as $table_name ) {
            $safe_table_name = esc_sql( $table_name );
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery
            $wpdb->query( "DROP TABLE IF EXISTS `{$safe_table_name}`" ); // nosemgrep  // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared,WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- internal schema identifier only.
        }

        do_action( 'ultraguard_pro/module_schema_uninstalled', $this->get_module_id() );
    }

    // ── Helpers ───────────────────────────────────────────────────────────────

    /**
     * Resolve the fully-prefixed table name.
     *
     * @param  string $unprefixed  e.g. 'ultraguard_scan_results'
     * @return string              e.g. 'wp_ultraguard_scan_results'
     */
    protected function table( string $unprefixed ): string {
        global $wpdb;
        return $wpdb->prefix . $unprefixed;
    }

    /**
     * Return the database character-set and collation clause.
     * Used at the end of every CREATE TABLE statement.
     *
     * @return string  e.g. "CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci"
     */
    protected function charset_collate(): string {
        global $wpdb;
        return $wpdb->get_charset_collate();
    }
}
