<?php
/**
 * AF_Keepalive_Installer
 *
 * Copies inc/keepalive/auctionforge-keepalive.template.php into
 * wp-content/mu-plugins/auctionforge-keepalive.php on every successful AF
 * load. The point of the mu-plugin is to reactivate AF if a failed
 * update knocks it out — but for that to be possible, the mu-plugin
 * needs to already be on disk before the failure happens. Self-installing
 * during a successful load is the bootstrap mechanism.
 *
 * Idempotent:
 *   - Compares the source template's KEEPALIVE_VERSION header against
 *     the installed file. Re-writes only on bump (or when missing).
 *   - Won't touch a file at the destination path that doesn't have our
 *     "AuctionForge Keepalive" Plugin Name marker — defensive against
 *     stomping on someone else's mu-plugin with a name collision.
 *
 * Failure modes are logged to wp_options for wpdeploy visibility but
 * never throw — keepalive install is best-effort, AF should still load
 * even if mu-plugins/ is read-only.
 */

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

class AF_Keepalive_Installer {

    const SOURCE_RELATIVE = '/inc/keepalive/auctionforge-keepalive.template.php';
    const DEST_NAME       = 'auctionforge-keepalive.php';
    const MARKER          = 'AuctionForge Keepalive';

    public static function maybe_install() {
        $src = self::source_path();
        if (!file_exists($src)) return false;

        $mu_dir = WP_CONTENT_DIR . '/mu-plugins';
        $dest   = $mu_dir . '/' . self::DEST_NAME;

        if (!is_dir($mu_dir)) {
            if (!@mkdir($mu_dir, 0755, true) && !is_dir($mu_dir)) {
                self::record_failure('mu_plugins_dir_create_failed');
                return false;
            }
        }

        $src_version = self::extract_version($src);

        if (file_exists($dest)) {
            $head = @file_get_contents($dest, false, null, 0, 4096);
            if ($head === false || stripos($head, self::MARKER) === false) {
                // Some other file is squatting the destination — don't stomp.
                self::record_failure('foreign_file_at_dest');
                return false;
            }
            $dest_version = self::extract_version($dest);
            if ($dest_version === $src_version) {
                return true; // already at latest, nothing to do
            }
        }

        $written = @copy($src, $dest);
        if (!$written) {
            self::record_failure('copy_failed');
            return false;
        }
        @chmod($dest, 0644);

        update_option('auctionforge_keepalive_installed_version', $src_version, 'no');
        update_option('auctionforge_keepalive_installed_at', current_time('mysql', true), 'no');
        delete_option('auctionforge_keepalive_install_error');
        return true;
    }

    private static function source_path() {
        // Plugin file → plugin dir. AF's main plugin file is two levels up.
        return dirname(__DIR__, 2) . self::SOURCE_RELATIVE;
    }

    private static function extract_version($file) {
        $head = @file_get_contents($file, false, null, 0, 4096);
        if ($head === false) return '0.0.0';
        if (preg_match('/^\s*\*\s*KEEPALIVE_VERSION:\s*([\d.]+)/m', $head, $m)) {
            return $m[1];
        }
        return '0.0.0';
    }

    private static function record_failure($reason) {
        update_option('auctionforge_keepalive_install_error', $reason, 'no');
        update_option('auctionforge_keepalive_install_error_at', current_time('mysql', true), 'no');
    }
}
