<?php

/**
 * Code Injection Module
 *
 * Outputs user-defined code snippets in the document head, body open, and
 * footer on frontend requests only. Skips REST, feed, sitemap, admin, and
 * login contexts to avoid side-effects.
 *
 * @package ProRank\SEO\Modules\Core
 * @since   1.0.11
 */

declare(strict_types=1);

namespace ProRank\SEO\Modules\Core;

use ProRank\SEO\Modules\BaseModule;

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

class CodeInjectionModule extends BaseModule {

    protected string $slug = 'code-injection';

    protected string $name = 'Code Injection';

    protected string $description = 'Add custom code snippets to the head, body, and footer of your site.';

    protected string $feature_tier = 'free';

    protected ?string $parent_slug = 'support-account';

    /**
     * Cached settings.
     */
    private ?array $settings = null;

    /**
     * Guard against duplicate output.
     */
    private bool $head_rendered = false;
    private bool $body_rendered = false;
    private bool $footer_rendered = false;

    public function init_hooks(): void {
        // Only run on true frontend page loads.
        if ( $this->is_excluded_context() ) {
            return;
        }

        add_action( 'wp_head', [ $this, 'render_head_code' ], 1 );
        add_action( 'wp_body_open', [ $this, 'render_body_code' ], 1 );
        add_action( 'wp_footer', [ $this, 'render_footer_code' ], 999 );
    }

    /**
     * Output head code.
     */
    public function render_head_code(): void {
        if ( $this->head_rendered ) {
            return;
        }
        $this->head_rendered = true;

        $code = trim( $this->get_injection_setting( 'head_code' ) );
        if ( $code !== '' ) {
            echo "\n<!-- ProRank head code -->\n" . $code . "\n";
        }
    }

    /**
     * Output body-open code.
     */
    public function render_body_code(): void {
        if ( $this->body_rendered ) {
            return;
        }
        $this->body_rendered = true;

        $code = trim( $this->get_injection_setting( 'body_code' ) );
        if ( $code !== '' ) {
            echo "\n<!-- ProRank body code -->\n" . $code . "\n";
        }
    }

    /**
     * Output footer code.
     */
    public function render_footer_code(): void {
        if ( $this->footer_rendered ) {
            return;
        }
        $this->footer_rendered = true;

        $code = trim( $this->get_injection_setting( 'footer_code' ) );
        if ( $code !== '' ) {
            echo "\n<!-- ProRank footer code -->\n" . $code . "\n";
        }
    }

    /**
     * Check whether the current request should be excluded from code output.
     */
    private function is_excluded_context(): bool {
        // Admin / login pages.
        if ( is_admin() || $this->is_login_page() ) {
            return true;
        }

        // REST API.
        if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
            return true;
        }

        // AJAX.
        if ( wp_doing_ajax() ) {
            return true;
        }

        // Cron.
        if ( wp_doing_cron() ) {
            return true;
        }

        // WP-CLI.
        if ( defined( 'WP_CLI' ) && WP_CLI ) {
            return true;
        }

        // XML sitemap requests (ProRank or Rank Math patterns).
        $uri = $_SERVER['REQUEST_URI'] ?? '';
        if ( preg_match( '/sitemap.*\.xml/i', $uri ) ) {
            return true;
        }

        // Feed requests.
        if ( preg_match( '/\/feed\/?$/i', $uri ) ) {
            return true;
        }

        return false;
    }

    /**
     * Detect WordPress login page.
     */
    private function is_login_page(): bool {
        return in_array(
            $GLOBALS['pagenow'] ?? '',
            [ 'wp-login.php', 'wp-register.php' ],
            true
        );
    }

    /**
     * Retrieve a single injection setting value.
     */
    private function get_injection_setting( string $key ): string {
        $settings = $this->get_injection_settings();
        return (string) ( $settings[ $key ] ?? '' );
    }

    /**
     * Load settings from the database.
     */
    private function get_injection_settings(): array {
        if ( $this->settings === null ) {
            $defaults = [
                'head_code'   => '',
                'body_code'   => '',
                'footer_code' => '',
            ];

            $this->settings = wp_parse_args(
                get_option( 'prorank_seo_code_injection', [] ),
                $defaults
            );
        }

        return $this->settings;
    }
}
