<?php
/**
 * Admin Area wrapper.
 *
 * @package NimblyMail\SMTP
 */

namespace NimblyMail\SMTP\Admin;

use NimblyMail\SMTP\Options;

defined( 'ABSPATH' ) || exit;

/**
 * Class Area
 *
 * Registers the WordPress admin menu and enqueues the Vite apps.
 *
 * @since 1.0.0
 */
class Area {

    /**
     * Whether HMR dev mode is enabled.
     *
     * @since 1.0.0
     *
     * @var bool
     */
    private bool $is_hmr_enabled = false;

    /**
     * Dev server base URL parsed from .env.
     *
     * @since 1.0.0
     *
     * @var string
     */
    private string $dev_base_url = 'http://localhost:5174';

    /**
     * Parsed .env values.
     *
     * @since 1.0.0
     *
     * @var array
     */
    private array $env = array();

    /**
     * Map of admin page hook suffixes to their Vue app config.
     *
     * @since 1.0.0
     *
     * @var array
     */
    private array $apps = array();

    /**
     * Constructor.
     *
     * @since 1.0.0
     */
    public function __construct() {
        $hmr_dev = defined( 'HMR_DEV' ) ? HMR_DEV : false;

        if ( 'nimblymail-smtp' === $hmr_dev ) {
            $this->is_hmr_enabled = true;
            $this->parse_env();

            $host = $this->env['VITE_DEV_SERVER_HOST'] ?? 'localhost';
            $port = $this->env['VITE_DEV_SERVER_PORT'] ?? '5174';

            $this->dev_base_url = $this->env['VITE_DEV_SERVER_ORIGIN']
                ?? 'http://' . $host . ':' . $port;
        }

        $this->apps = array(
            'toplevel_page_nimblymail-smtp'            => array(
                'entry'    => 'apps/dashboard/index.ts',
                'handle'   => 'nimblymail-smtp-dashboard',
                'localize' => 'nimblymailSmtpApp',
            ),
            'nimblymail_page_nimblymail-smtp-settings' => array(
                'entry'    => 'apps/settings/index.ts',
                'handle'   => 'nimblymail-smtp-settings',
                'localize' => 'nimblymailSmtpApp',
            ),
            'nimblymail_page_nimblymail-smtp-logs'     => array(
                'entry'    => 'apps/email-logs/index.ts',
                'handle'   => 'nimblymail-smtp-logs',
                'localize' => 'nimblymailSmtpApp',
            ),
            'nimblymail_page_nimblymail-smtp-queue'    => array(
                'entry'    => 'apps/queue/index.ts',
                'handle'   => 'nimblymail-smtp-queue',
                'localize' => 'nimblymailSmtpApp',
            ),
            'nimblymail_page_nimblymail-smtp-tools'    => array(
                'entry'    => 'apps/tools/index.ts',
                'handle'   => 'nimblymail-smtp-tools',
                'localize' => 'nimblymailSmtpApp',
            ),
            'nimblymail_page_nimblymail-smtp-deliverability' => array(
                'entry'    => 'apps/deliverability/index.ts',
                'handle'   => 'nimblymail-smtp-deliverability',
                'localize' => 'nimblymailSmtpApp',
            ),
            'admin_page_nimblymail-smtp-setup-wizard'  => array(
                'entry'    => 'apps/wizard/index.ts',
                'handle'   => 'nimblymail-smtp-wizard',
                'localize' => 'nimblymailSmtpApp',
            ),
        );
    }

    /**
     * Initialize admin hooks.
     *
     * @since 1.0.0
     */
    public function init(): void {
        add_action( 'admin_menu', array( $this, 'add_menu_pages' ) );
        add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ) );
        add_filter( 'script_loader_tag', array( $this, 'add_module_to_script_tag' ), 10, 2 );
        add_filter( 'plugin_action_links_' . NIMBLYMAIL_BASENAME, array( $this, 'add_action_links' ) );
    }

    /**
     * Add Settings (and conditionally Go Pro) links to the plugin row on the
     * Plugins page.
     *
     * Settings is prepended ahead of the WordPress-supplied Activate /
     * Deactivate / Edit cluster so it lines up with the Plugins-page
     * convention. When Pro is not active and the current viewer can act on
     * the upsell ({@see Plugin::can_show_upsell()}), a quietly-coloured "Go
     * Pro" link is appended after Settings — opens in a new tab with
     * `rel="noopener noreferrer"` to prevent tabnabbing.
     *
     * @since 1.0.0
     *
     * @param array $links Existing action links.
     *
     * @return array Modified action links.
     */
    public function add_action_links( array $links ): array {
        $custom = array(
            'settings' => sprintf(
                '<a href="%s">%s</a>',
                esc_url( admin_url( 'admin.php?page=nimblymail-smtp-settings#/settings/general' ) ),
                esc_html__( 'Settings', 'nimblymail-smtp' )
            ),
        );

        $plugin = nimblymail();
        if ( $plugin->can_show_upsell( 'site' ) ) {
            $custom['go_pro'] = sprintf(
                '<a href="%s" target="_blank" rel="noopener noreferrer" style="color:#1da867;font-weight:600;">%s</a>',
                esc_url( $plugin->get_pro_url( 'plugin-row' ) ),
                esc_html__( 'Go Pro', 'nimblymail-smtp' )
            );
        }

        return array_merge( $custom, $links );
    }

    /**
     * Add menu and submenu pages.
     *
     * Registers all built-in menu and submenu pages then fires the
     * nimblymail_admin_menu action so Pro add-ons can register additional
     * submenu pages under the NimblyMail parent slug.
     *
     * @since 1.0.0 Added nimblymail_admin_menu action for Pro add-ons.
     *
     * @return void
     */
    public function add_menu_pages(): void {
        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
        $icon_svg = file_get_contents( NIMBLYMAIL_PATH . 'assets/images/logo/nimblymail-smtp-icon-menu.svg' );
        // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode -- Base64-encoding SVG for WP admin menu icon data URI.
        $icon_url = 'data:image/svg+xml;base64,' . base64_encode( $icon_svg );

        add_menu_page(
            __( 'NimblyMail', 'nimblymail-smtp' ),
            __( 'NimblyMail', 'nimblymail-smtp' ),
            'manage_options',
            'nimblymail-smtp',
            array( $this, 'render_dashboard_page' ),
            $icon_url,
            81
        );

        add_submenu_page(
            'nimblymail-smtp',
            __( 'Dashboard', 'nimblymail-smtp' ),
            __( 'Dashboard', 'nimblymail-smtp' ),
            'manage_options',
            'nimblymail-smtp',
            array( $this, 'render_dashboard_page' )
        );

        // Email Logs submenu is hidden when email logging is disabled.
        if ( (bool) Options::init()->get( 'logs', 'enabled' ) ) {
            add_submenu_page(
                'nimblymail-smtp',
                __( 'Email Logs', 'nimblymail-smtp' ),
                __( 'Email Logs', 'nimblymail-smtp' ),
                'manage_options',
                'nimblymail-smtp-logs',
                array( $this, 'render_logs_page' )
            );
        }

        // Queue submenu is hidden when the mail queue is disabled.
        if ( (bool) Options::init()->get( 'queue', 'enabled' ) ) {
            add_submenu_page(
                'nimblymail-smtp',
                __( 'Queue', 'nimblymail-smtp' ),
                __( 'Queue', 'nimblymail-smtp' ),
                'manage_options',
                'nimblymail-smtp-queue',
                array( $this, 'render_queue_page' )
            );
        }

        add_submenu_page(
            'nimblymail-smtp',
            __( 'Tools', 'nimblymail-smtp' ),
            __( 'Tools', 'nimblymail-smtp' ),
            'manage_options',
            'nimblymail-smtp-tools',
            array( $this, 'render_tools_page' )
        );

        add_submenu_page(
            'nimblymail-smtp',
            __( 'Deliverability', 'nimblymail-smtp' ),
            __( 'Deliverability', 'nimblymail-smtp' ),
            'manage_options',
            'nimblymail-smtp-deliverability',
            array( $this, 'render_deliverability_page' )
        );

        add_submenu_page(
            'nimblymail-smtp',
            __( 'Settings', 'nimblymail-smtp' ),
            __( 'Settings', 'nimblymail-smtp' ),
            'manage_options',
            'nimblymail-smtp-settings',
            array( $this, 'render_settings_page' )
        );

        /**
         * Fires after all built-in NimblyMail submenu pages are registered.
         *
         * Allows Pro add-ons to register additional submenu pages under the
         * NimblyMail parent menu slug using standard WordPress APIs.
         *
         * @since 1.0.0
         *
         * @param string $parent_slug The NimblyMail top-level menu slug.
         */
        do_action( 'nimblymail_admin_menu', 'nimblymail-smtp' );
    }

    /**
     * Render the dashboard Vue mount point.
     *
     * @since 1.0.0
     */
    public function render_dashboard_page(): void {
        echo '<div class="wrap"><div id="nimblymail-smtp-dashboard"></div></div>';
    }

    /**
     * Render the settings Vue mount point.
     *
     * @since 1.0.0
     */
    public function render_settings_page(): void {
        echo '<div class="wrap"><div id="nimblymail-smtp-app"></div></div>';
    }

    /**
     * Render the email logs Vue mount point.
     *
     * @since 1.0.0
     */
    public function render_logs_page(): void {
        echo '<div class="wrap"><div id="nimblymail-smtp-logs"></div></div>';
    }

    /**
     * Render the queue Vue mount point.
     *
     * @since 1.0.0
     */
    public function render_queue_page(): void {
        echo '<div class="wrap"><div id="nimblymail-smtp-queue"></div></div>';
    }

    /**
     * Render the tools Vue mount point.
     *
     * @since 1.0.0
     */
    public function render_tools_page(): void {
        echo '<div class="wrap"><div id="nimblymail-smtp-tools"></div></div>';
    }

    /**
     * Render the deliverability Vue mount point.
     *
     * @since 1.0.0
     */
    public function render_deliverability_page(): void {
        echo '<div class="wrap"><div id="nimblymail-smtp-deliverability"></div></div>';
    }

    /**
     * Enqueue Vite dev server or production assets for the current page.
     *
     * @since 1.0.0 Added wizard schema localization and extension hook.
     *
     * @param string $hook_suffix The current admin page.
     */
    public function enqueue_assets( string $hook_suffix ): void {
        if ( ! isset( $this->apps[ $hook_suffix ] ) ) {
            return;
        }

        $app = $this->apps[ $hook_suffix ];

        $sandbox_options = Options::init();
        $sandbox_active  = (bool) $sandbox_options->get( 'sandbox', 'enabled' );
        $sandbox_mode    = $sandbox_active ? (string) $sandbox_options->get( 'sandbox', 'mode' ) : null;
        $do_not_send     = (bool) $sandbox_options->get( 'general', 'do_not_send' );
        $env_type        = function_exists( 'wp_get_environment_type' ) ? wp_get_environment_type() : 'production';

        $plugin = nimblymail();

        $localize_data = array(
            'root'          => esc_url_raw( rest_url() ),
            'nonce'         => wp_create_nonce( 'wp_rest' ),
            'pluginUrl'     => NIMBLYMAIL_URL,
            'assetsUrl'     => NIMBLYMAIL_URL . 'dist/assets/',
            'adminUrl'      => admin_url( 'admin.php' ),
            'isDevMode'     => $this->is_hmr_enabled,
            'adminEmail'    => get_option( 'admin_email' ),
            'isMultisite'   => is_multisite(),
            'context'       => 'site',
            'sandboxActive' => $sandbox_active,
            'sandboxMode'   => $sandbox_mode,
            'doNotSend'     => $do_not_send,
            'envType'       => $env_type,
            'proActive'     => $plugin->is_pro_active(),
            'canShowUpsell' => $plugin->can_show_upsell( 'site' ),
            'proUrl'        => $plugin->get_pro_url( 'plugin' ),
        );

        if ( 'nimblymail-smtp-wizard' === $app['handle'] ) {
            $localize_data['wizardSteps'] = SetupWizard::get_steps_schema();
        }

        AssetLoader::enqueue( $app['handle'], $app['entry'], $localize_data, $this->is_hmr_enabled, $this->dev_base_url );

        if ( 'nimblymail-smtp-wizard' === $app['handle'] ) {
            /**
             * Fires after the wizard bundle has been enqueued.
             *
             * Pro add-ons hook here to enqueue an extension bundle that
             * registers extra Vue components into the wizard registry. The
             * extension bundle MUST declare `nimblymail-smtp-wizard` as a
             * dependency so it loads after the core wizard registry is set
             * up but before the core wizard mounts (mounting is deferred to
             * the next macrotask).
             *
             * @since 1.0.0
             *
             * @param bool $is_hmr_enabled Whether the Vite dev server is in use.
             */
            do_action( 'nimblymail_wizard_enqueue_assets', $this->is_hmr_enabled );
        }
    }

    /**
     * Add type="module" to Vite script tags.
     *
     * @since 1.0.0
     *
     * @param string $tag    The script tag HTML.
     * @param string $handle The script handle.
     *
     * @return string
     */
    public function add_module_to_script_tag( string $tag, string $handle ): string {
        return AssetLoader::add_module_to_script_tag( $tag, $handle );
    }

    /**
     * Parse the .env file from the plugin root.
     *
     * @since 1.0.0
     */
    private function parse_env(): void {
        $env_path = NIMBLYMAIL_PATH . '.env';

        if ( ! file_exists( $env_path ) ) {
            return;
        }

        $lines = file( $env_path, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents

        if ( ! $lines ) {
            return;
        }

        foreach ( $lines as $line ) {
            $line = trim( $line );
            if ( '' === $line || str_starts_with( $line, '#' ) ) {
                continue;
            }

            $parts = explode( '=', $line, 2 );
            if ( count( $parts ) === 2 ) {
                $this->env[ trim( $parts[0] ) ] = trim( $parts[1] );
            }
        }
    }
}
