<?php

declare(strict_types=1);

namespace SiteFort\Modules\Hardening\Compatibility;

use SiteFort\Includes\Capabilities;

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

class ServerRulePluginConflictDetector {

    /**
     * @var array<int,string>
     */
    private const CONFLICTING_PLUGIN_FILES = [
        'better-wp-security/better-wp-security.php',
        'defender-security/wp-defender.php',
        'hide-my-wp/index.php',
    ];

    public static function render_admin_notice(): void {
        if ( ! Capabilities::can_manage_plugin() ) {
            return;
        }

        $plugins = self::get_active_conflicting_plugins();
        if ( $plugins === [] ) {
            return;
        }

        $labels       = array_values( $plugins );
        $plugin_label = self::format_plugin_list( $labels );
        $verb         = count( $labels ) === 1 ? 'is' : 'are';
        $manage_url   = self::get_manage_plugins_url( $labels );
        $message      = sprintf(
            '%s %s active and may apply server-level hardening that overlaps with SiteFort. Review the active security plugin settings to prevent conflicting rules or unexpected site behavior.',
            $plugin_label,
            $verb
        );
        ?>
        <div class="notice notice-warning sitefort-compatibility-notice">
            <div class="sitefort-compatibility-notice-content">
                <p class="sitefort-compatibility-notice-message"><strong><?php esc_html_e( 'SiteFort compatibility advisory:', 'sitefort' ); ?></strong> <?php echo esc_html( $message ); ?></p>
                <p class="sitefort-compatibility-notice-action"><a class="button button-primary" href="<?php echo esc_url( $manage_url ); ?>"><?php esc_html_e( 'Manage Installed Plugins', 'sitefort' ); ?></a></p>
            </div>
        </div>
        <?php
    }

    /**
     * @return array<string,string>
     */
    private static function get_active_conflicting_plugins(): array {
        $active_plugin_files      = self::get_active_plugin_files();
        $active_conflicting_files = array_values(
            array_intersect( $active_plugin_files, self::CONFLICTING_PLUGIN_FILES )
        );

        if ( $active_conflicting_files === [] ) {
            return [];
        }

        $active = [];
        $names  = self::get_plugin_names();

        foreach ( $active_conflicting_files as $plugin_file ) {
            $active[ $plugin_file ] = $names[ $plugin_file ] ?? self::fallback_plugin_name( $plugin_file );
        }

        return $active;
    }

    /**
     * @return array<string,string>
     */
    private static function get_plugin_names(): array {
        if ( ! function_exists( 'get_plugins' ) ) {
            $plugin_functions = ABSPATH . 'wp-admin/includes/plugin.php';
            if ( is_file( $plugin_functions ) ) {
                require_once $plugin_functions;
            }
        }

        if ( ! function_exists( 'get_plugins' ) ) {
            return [];
        }

        $plugins = get_plugins();
        if ( ! is_array( $plugins ) ) {
            return [];
        }

        $names = [];
        foreach ( $plugins as $plugin_file => $plugin_data ) {
            if ( ! is_string( $plugin_file ) || ! is_array( $plugin_data ) ) {
                continue;
            }

            $name = is_string( $plugin_data['Name'] ?? null ) ? trim( (string) $plugin_data['Name'] ) : '';
            if ( $name !== '' ) {
                $names[ $plugin_file ] = $name;
            }
        }

        return $names;
    }

    private static function fallback_plugin_name( string $plugin_file ): string {
        $basename = basename( $plugin_file, '.php' );
        if ( in_array( strtolower( $basename ), [ 'index', 'plugin', 'main' ], true ) ) {
            $directory = basename( dirname( $plugin_file ) );
            if ( $directory !== '' && $directory !== '.' ) {
                $basename = $directory;
            }
        }

        $basename = str_replace( [ '-', '_' ], ' ', $basename );
        $basename = trim( preg_replace( '/\s+/', ' ', $basename ) ?? $basename );

        if ( $basename === '' ) {
            return $plugin_file;
        }

        $label = ucwords( $basename );
        $label = preg_replace( '/\bWp\b/', 'WP', $label );

        return is_string( $label ) && $label !== '' ? $label : $plugin_file;
    }

    /**
     * @param array<int,string> $labels
     */
    private static function format_plugin_list( array $labels ): string {
        if ( count( $labels ) <= 1 ) {
            return (string) ( $labels[0] ?? '' );
        }

        $last = array_pop( $labels );

        return implode( ', ', $labels ) . ' and ' . $last;
    }

    /**
     * @param array<int,string> $labels
     */
    private static function get_manage_plugins_url( array $labels ): string {
        $url = self::has_network_active_conflicting_plugin() ? network_admin_url( 'plugins.php' ) : admin_url( 'plugins.php' );

        if ( count( $labels ) === 1 && $labels[0] !== '' ) {
            $url = add_query_arg(
                [
                    'plugin_status' => 'all',
                    's'             => $labels[0],
                ],
                $url
            );
        }

        return $url;
    }

    private static function has_network_active_conflicting_plugin(): bool {
        if ( ! is_multisite() ) {
            return false;
        }

        $network_plugins = get_site_option( 'active_sitewide_plugins', [] );
        if ( ! is_array( $network_plugins ) ) {
            return false;
        }

        foreach ( array_keys( $network_plugins ) as $plugin_file ) {
            if ( is_string( $plugin_file ) && in_array( $plugin_file, self::CONFLICTING_PLUGIN_FILES, true ) ) {
                return true;
            }
        }

        return false;
    }

    /**
     * @return array<int,string>
     */
    private static function get_active_plugin_files(): array {
        $active_plugins = get_option( 'active_plugins', [] );
        if ( ! is_array( $active_plugins ) ) {
            $active_plugins = [];
        }

        $plugin_files = array_values(
            array_filter(
                $active_plugins,
                static fn( $plugin ) => is_string( $plugin ) && $plugin !== ''
            )
        );

        if ( is_multisite() ) {
            $network_plugins = get_site_option( 'active_sitewide_plugins', [] );
            if ( is_array( $network_plugins ) ) {
                $plugin_files = array_merge(
                    $plugin_files,
                    array_values(
                        array_filter(
                            array_keys( $network_plugins ),
                            static fn( $plugin ) => is_string( $plugin ) && $plugin !== ''
                        )
                    )
                );
            }
        }

        return array_values( array_unique( $plugin_files ) );
    }
}
