<?php

declare(strict_types=1);

namespace SiteFort\Includes;

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

/**
 * Hosting platform classification.
 *
 * Single source of truth for "what kind of managed host are we on?".
 * Drives WAF capability decisions: hosts in this list lock down PHP-FPM
 * such that user-managed auto_prepend_file directives (.htaccess /
 * .user.ini) are ignored, so SiteFort must fall back to a must-use plugin
 * loader instead.
 *
 * Detection requires strong runtime signals (host-defined $_SERVER keys,
 * environment variables, or platform constants). Static evidence such as
 * a vendor mu-plugin file is never sufficient on its own because a
 * migrated site may carry that tree without actually running on the
 * platform that produced it.
 */
final class HostingPlatform {

    public const PLATFORM_NONE      = '';
    public const PLATFORM_WP_ENGINE = 'wp_engine';
    public const PLATFORM_FLYWHEEL  = 'flywheel';
    public const PLATFORM_PRESSABLE = 'pressable';
    public const PLATFORM_KINSTA    = 'kinsta';
    public const PLATFORM_PANTHEON  = 'pantheon';
    public const PLATFORM_VIP       = 'wpcom_vip';

    /** @var string|null */
    private static $cached = null;

    /**
     * Resolve the current hosting platform.
     *
     * Filterable via the `sitefort_hosting_platform` filter so integrations
     * can override classification without a code release.
     */
    public static function detect(): string {
        if ( self::$cached !== null ) {
            return self::$cached;
        }

        $platform = self::detect_uncached();

        if ( function_exists( 'apply_filters' ) ) {
            $filtered = apply_filters( 'sitefort_hosting_platform', $platform );
            if ( is_string( $filtered ) ) {
                $platform = $filtered;
            }
        }

        self::$cached = $platform;
        return $platform;
    }

    public static function reset_cache(): void {
        self::$cached = null;
    }

    /**
     * True when the current host belongs to the lockdown tier.
     *
     * Lockdown hosts run PHP-FPM pools the customer cannot reconfigure,
     * so SiteFort uses the Early Loader fallback.
     */
    public static function is_locked_down_managed(): bool {
        return self::detect() !== self::PLATFORM_NONE;
    }

    public static function label(): string {
        switch ( self::detect() ) {
            case self::PLATFORM_WP_ENGINE: return 'WP Engine';
            case self::PLATFORM_FLYWHEEL:  return 'Flywheel';
            case self::PLATFORM_PRESSABLE: return 'Pressable';
            case self::PLATFORM_KINSTA:    return 'Kinsta';
            case self::PLATFORM_PANTHEON:  return 'Pantheon';
            case self::PLATFORM_VIP:       return 'WordPress VIP';
            default: return '';
        }
    }

    private static function detect_uncached(): string {
        if ( self::server_key_exists( 'IS_WPE' ) ) {
            return self::PLATFORM_WP_ENGINE;
        }

        if ( strpos( self::server_value( 'SERVER_SOFTWARE' ), 'Flywheel/' ) === 0 ) {
            return self::PLATFORM_FLYWHEEL;
        }

        if ( ( defined( 'WPCOM_IS_VIP_ENV' ) && (bool) constant( 'WPCOM_IS_VIP_ENV' ) )
            || defined( 'VIP_GO_APP_ENVIRONMENT' )
        ) {
            return self::PLATFORM_VIP;
        }

        if ( defined( 'IS_PRESSABLE' ) && (bool) constant( 'IS_PRESSABLE' ) ) {
            return self::PLATFORM_PRESSABLE;
        }

        if ( defined( 'IS_ATOMIC' ) && (bool) constant( 'IS_ATOMIC' ) ) {
            return self::PLATFORM_PRESSABLE;
        }

        if ( self::server_key_exists( 'PANTHEON_ENVIRONMENT' )
            || self::env_value( 'PANTHEON_ENVIRONMENT' ) !== ''
            || defined( 'PANTHEON_ENVIRONMENT' )
        ) {
            return self::PLATFORM_PANTHEON;
        }

        if ( self::is_kinsta_runtime() ) {
            return self::PLATFORM_KINSTA;
        }

        return self::PLATFORM_NONE;
    }

    /**
     * Multi-signal Kinsta detection.
     *
     * The kinsta-mu-plugins directory is intentionally NOT a sufficient
     * signal: migrated sites carry the directory in their wp-content
     * tree without actually running on Kinsta's stack.
     */
    private static function is_kinsta_runtime(): bool {
        $runtime_keys = [
            'KINSTA_CACHE_ZONE',
            'KINSTAMU_VERSION',
            'KINSTA_SERVICE_NAME',
            'KINSTA_HOSTNAME_PREFIX',
        ];

        foreach ( $runtime_keys as $key ) {
            if ( self::server_key_exists( $key ) ) {
                return true;
            }
            if ( self::env_value( $key ) !== '' ) {
                return true;
            }
        }

        $host = strtolower( self::server_value( 'HTTP_HOST' ) );
        if ( $host !== '' ) {
            $managed_suffixes = [ '.kinsta.cloud', '.kinsta.app' ];
            foreach ( $managed_suffixes as $suffix ) {
                $offset = strlen( $host ) - strlen( $suffix );
                if ( $offset >= 0 && substr( $host, $offset ) === $suffix ) {
                    return true;
                }
            }
        }

        return false;
    }

    private static function server_key_exists( string $key ): bool {
        return isset( $_SERVER[ $key ] ) && ! is_array( $_SERVER[ $key ] );
    }

    private static function server_value( string $key ): string {
        if ( ! isset( $_SERVER[ $key ] ) || is_array( $_SERVER[ $key ] ) ) {
            return '';
        }

        $value = sanitize_text_field( wp_unslash( (string) $_SERVER[ $key ] ) );
        return strpos( $value, "\0" ) !== false ? '' : $value;
    }

    private static function env_value( string $key ): string {
        if ( isset( $_ENV[ $key ] ) && ! is_array( $_ENV[ $key ] ) ) {
            $value = sanitize_text_field( wp_unslash( (string) $_ENV[ $key ] ) );
            if ( $value !== '' && strpos( $value, "\0" ) === false ) {
                return $value;
            }
        }

        $raw = getenv( $key );
        if ( ! is_string( $raw ) ) {
            return '';
        }

        $value = sanitize_text_field( $raw );
        return strpos( $value, "\0" ) !== false ? '' : $value;
    }
}
