<?php

namespace Twnt4All;

use Twnt4All\Backend\FileServer;
use Twnt4All\Backend\ConfigPage;
use Twnt4All\Backend\SchemaMigrator;
use Twnt4All\Backend\AdminAjax;
use Twnt4All\Backend\WooTeaser;
use Twnt4All\Engine\Support\MarkupBuilder;
use Twnt4All\Support\WpBridge;
use Twnt4All\Support\Paths;
use Twnt4All\Engine\Adapter\DomainEvents;

/**
 * Class Bootstrap
 *
 * Free plugin (WP.org) entry point. Contains NO WooCommerce runtime code.
 * The WooCommerce gateway (including checkout, blocks, refunds, monitoring)
 * lives in the paid companion plugin `pay4all-pro` under
 * `src/Integrations/Twint/`. That companion wires itself up when both
 * `pay4all-for-twint` and WooCommerce are present.
 *
 * On its own, this plugin exposes:
 *   - the TWINT admin wizard (3 steps: intro, credentials, status),
 *   - the Pay4All Shop integration (form-based checkout) that consumes the
 *     shared TWINT SOAP engine.
 *
 * @package Twnt4All
 */
class Bootstrap
{
    /**
     * Bootstrap constructor.
     */
    public function __construct()
    {
        include_once __DIR__ . '/constants.php';
        include_once __DIR__ . '/Support/templating.php';

        if ( T4A_OPENSSL_ACTIVE ) {
            add_filter( 'upload_mimes', [ $this, 'upload_mimes' ] );
        }

        register_activation_hook( T4A_PLUGIN_FILE, [ $this, 'on_activation' ] );
        register_deactivation_hook( T4A_PLUGIN_FILE, [ $this, 'on_deactivation' ] );

        add_action( 'admin_enqueue_scripts', [ $this, 'admin_styles' ] );
        add_action( 'plugins_loaded', [ $this, 'on_plugins_loaded' ] );

        add_action( 'init', [ $this, 'download_file' ] );
        add_action( 'init', [ $this, 'print_file' ] );
    }

    /**
     * Registers the PSR-4 autoloader and boots the Pay4All Shop integration.
     * Called on every request from on_plugins_loaded().
     */
    private function include_files_core()
    {
        spl_autoload_register( function ( $class_name ) {
            if ( strpos( $class_name, 'Twnt4All\\' ) !== 0 ) {
                return;
            }
            $relative  = str_replace( '\\', DIRECTORY_SEPARATOR, substr( $class_name, strlen( 'Twnt4All\\' ) ) );
            $file_path = __DIR__ . DIRECTORY_SEPARATOR . $relative . '.php';
            if ( file_exists( $file_path ) ) {
                require_once $file_path;
            }
        } );

        include_once __DIR__ . DIRECTORY_SEPARATOR . 'Engine' . DIRECTORY_SEPARATOR . 'constants.php';
        include_once __DIR__ . DIRECTORY_SEPARATOR . 'Engine' . DIRECTORY_SEPARATOR . 'exceptions.php';

        // Pay4All Shop (pay4all-form) integration — form-based checkout that
        // consumes the shared TWINT SOAP engine.
        \Twnt4All\Pay4All\Bootstrap::run();
    }

    /**
     * @param $mimes
     * @return mixed
     */
    public function upload_mimes( $mimes )
    {
        if ( current_user_can( 'administrator' ) ) {
            $mimes[ 'p12' ] = 'application/pkcs-12';
            $mimes[ 'pfx' ] = 'application/x-pkcs12';
            $mimes[ 'pem' ] = 'application/x-pem-file';
            $mimes[ 'txt' ] = 'text/plain';
        }
        return $mimes;
    }

    public function on_activation()
    {
        flush_rewrite_rules();
    }

    public function on_deactivation()
    {
    }

    /**
     * Enqueue admin assets on the wizard settings screen only.
     */
    public function admin_styles()
    {
        $current_screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
        if ( ! $current_screen ) {
            return;
        }
        if ( $current_screen->base !== 'toplevel_page_pay4all-settings'
             && strpos( (string) $current_screen->id, 'pay4all-settings' ) === false ) {
            return;
        }

        wp_enqueue_style(
            't4a_twint_admin_style',
            plugin_dir_url( dirname( __FILE__ ) ) . 'assets/css/admin-styles.css',
            [],
            T4A_PLUGIN_VERSION
        );

        wp_register_script(
            't4a_twint_admin',
            plugin_dir_url( dirname( __FILE__ ) ) . 'assets/js/twint.js',
            [ 'jquery' ],
            T4A_PLUGIN_VERSION,
            true
        );
        wp_localize_script( 't4a_twint_admin', 't4aTwintVars', [
            'ajaxUrl'   => admin_url( 'admin-ajax.php' ),
            'siteUrl'   => trailingslashit( get_site_url() ),
            'restUrl'   => trailingslashit( get_rest_url( null, 't4a/v1' ) ),
            'ajaxNonce' => wp_create_nonce( 'twnt_tw_license_nonce' ),
            'prefix'    => T4A_PREFIX,
            'texts'     => [
                'renewCertificateTitle' => __( 'Renew the certificate?', 'pay4all-for-twint' ),
                'renewCertificateText'  => __( 'If you have multiple shops connected to the same TWINT account please remember to copy the twint.pem file from the folder <strong>wp-content/uploads/t4a_twint</strong> to all other installations after the certificate renewal.', 'pay4all-for-twint' ),
                'confirmSettlement'     => __( 'Are you sure you want to confirm the transaction?', 'pay4all-for-twint' ),
                'confirmCancellation'   => __( 'Are you sure you want to cancel the transaction?', 'pay4all-for-twint' ),
                'errorInResponse'       => __( 'Error in response.', 'pay4all-for-twint' ),
            ],
        ] );
        wp_enqueue_script( 't4a_twint_admin' );
    }

    public function on_plugins_loaded()
    {
        // No explicit load_plugin_textdomain() call: since WP 4.6 core
        // just-in-time loads translations via the plugin header's
        // "Domain Path: /localization" declaration.
        //
        // Boot core (autoloader, engine constants, Pay4All Shop hooks) even
        // when neither Pay4All Shop nor WooCommerce is present : the wizard
        // and settings screen are useful on their own to configure /
        // validate TWINT credentials before installing a checkout host.
        // FormIntegration hooks are dormant filters - they only fire when
        // pay4all-form is loaded, so they are safe to register unconditionally.
        $this->include_files_core();

        // Informational notice when neither host is installed. Scoped to
        // the plugins page (WP.org Guideline 11 §18). Boot continues so the
        // wizard stays reachable.
        $has_p4form = class_exists( '\\Pay4All\\Form\\Plugin' )
            || defined( 'P4ALL_FORM_VERSION' )
            || post_type_exists( 'p4all_form' );
        $has_wc = class_exists( '\\WooCommerce' );
        if ( ! $has_p4form && ! $has_wc ) {
            add_action( 'admin_notices', static function () : void {
                $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
                if ( ! $screen || $screen->id !== 'plugins' ) { return; }
                echo '<div class="notice notice-error"><p>'
                    . esc_html__( 'Pay4All for TWINT requires WooCommerce or Pay4All Shop to be installed.', 'pay4all-for-twint' )
                    . '</p></div>';
            } );
        }

        if ( is_admin() && ! is_network_admin() ) {
            add_action( 'admin_menu', [ $this, 'add_admin_menu' ], 99 );
            // Process wizard POST submissions BEFORE WordPress emits any
            // admin chrome, so wp_safe_redirect() works in handle_wizard_post.
            add_action( 'admin_init', [ ConfigPage::class, 'maybe_handle_wizard_post' ] );
            // Upsell submenu — only shown when WooCommerce is active without
            // pay4all-pro. The class guards its own rendering conditions.
            WooTeaser::register();
        }

        // SOAP-required initialisation.
        if ( ! class_exists( '\\SoapClient' ) ) {
            add_action( 'admin_notices', [ $this, 'soap_not_enabled_notice' ] );
            return;
        }

        DomainEvents::init_actions();

        SchemaMigrator::init();
        SchemaMigrator::update_db();

        AdminAjax::init();

        add_filter( 'plugin_action_links_' . plugin_basename( T4A_PLUGIN_FILE ), [ $this, 'action_links' ] );
        add_filter( 'plugin_row_meta', [ $this, 'row_meta' ], 10, 2 );

        if ( is_admin() && ! is_network_admin() ) {
            ConfigPage::get_instance();
        }
    }

    public function add_admin_menu()
    {
        $cap     = 'manage_options';
        $top_lbl = __( 'Pay4All TWINT', 'pay4all-for-twint' );

        add_menu_page(
            $top_lbl,
            $top_lbl,
            $cap,
            'pay4all-settings',
            [ ConfigPage::class, 'render_admin_page' ],
            'dashicons-money-alt',
            81.5
        );

        add_submenu_page(
            'pay4all-settings',
            __( 'Settings', 'pay4all-for-twint' ),
            __( 'Settings', 'pay4all-for-twint' ),
            $cap,
            'pay4all-settings',
            [ ConfigPage::class, 'render_admin_page' ]
        );
    }

    /**
     * Add settings action links to plugins page
     *
     * @param array $links
     *
     * @return array
     */
    public function action_links( $links )
    {
        return array_merge(
            [ MarkupBuilder::a( __( 'Settings', 'pay4all-for-twint' ), admin_url( 'admin.php?page=pay4all-settings' ) ) ],
            $links
        );
    }

    /**
     * Replaces WP's auto-generated "Visit plugin site" link with a
     * "TWINT video guide" link pointing to the Pay4All tutorials page.
     *
     * @param array  $links Existing row-meta links.
     * @param string $file  Plugin file currently being rendered.
     * @return array
     */
    public function row_meta( $links, $file )
    {
        if ( $file !== plugin_basename( T4A_PLUGIN_FILE ) ) {
            return $links;
        }

        $doc_url = ConfigPage::get_documentation_url();
        $found   = false;
        foreach ( $links as $i => $link ) {
            if ( preg_match( '#<a [^>]*href=["\']https?://pay4all\.ch/?["\']#i', $link ) ) {
                $links[ $i ] = '<a href="' . esc_url( $doc_url ) . '" target="_blank" rel="noopener noreferrer">'
                    . esc_html__( 'TWINT video guide', 'pay4all-for-twint' )
                    . '</a>';
                $found = true;
                break;
            }
        }
        if ( ! $found ) {
            $links[] = '<a href="' . esc_url( $doc_url ) . '" target="_blank" rel="noopener noreferrer">'
                . esc_html__( 'TWINT video guide', 'pay4all-for-twint' )
                . '</a>';
        }
        return $links;
    }

    public function soap_not_enabled_notice()
    {
        // Scope to plugins.php only — WP.org Guideline 11 (§18) forbids
        // admin-wide banners. The merchant sees the notice exactly where
        // they can react (contact the host to enable the PHP SOAP ext).
        $screen = function_exists( 'get_current_screen' ) ? get_current_screen() : null;
        if ( ! $screen || $screen->id !== 'plugins' ) {
            return;
        }
        echo '<div class="error"><p>';
        esc_html_e( 'The SOAP extension is not enabled on your server. The payment method TWINT will not work if SOAP is not enabled.', 'pay4all-for-twint' );
        echo '</p></div>';
    }

    /**
     * Checks the request query args and sends the protected file.
     */
    public function download_file()
    {
        if ( ! isset( $_GET[ T4A_PREFIX . '-download' ] ) ) {
            return;
        }

        if ( ! current_user_can( 'manage_options' ) ) {
            return;
        }

        $nonce = isset( $_GET[ '_wpnonce' ] ) ? sanitize_text_field( wp_unslash( (string) $_GET[ '_wpnonce' ] ) ) : '';
        if ( ! wp_verify_nonce( $nonce, T4A_PREFIX . '_download_file' ) ) {
            return;
        }

        // phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized,WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- values are sanitised on the same line via sanitize_file_name / sanitize_key.
        if ( isset( $_GET[ T4A_PREFIX . "-type" ] ) && isset( $_GET[ T4A_PREFIX . "-file" ] ) && isset( $_GET[ T4A_PREFIX . "-name" ] ) ) {
            FileServer::send_file(
                sanitize_file_name( wp_unslash( (string) $_GET[ T4A_PREFIX . "-file" ] ) ),
                sanitize_key( wp_unslash( (string) $_GET[ T4A_PREFIX . "-type" ] ) ),
                sanitize_file_name( wp_unslash( (string) $_GET[ T4A_PREFIX . "-name" ] ) )
            );
        }
        // phpcs:enable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized,WordPress.Security.ValidatedSanitizedInput.MissingUnslash
    }

    /**
     * Opens the print screen of a file.
     */
    public function print_file()
    {
        if ( ! isset( $_GET[ T4A_PREFIX . '-print' ] ) ) {
            return;
        }

        if ( ! current_user_can( 'manage_options' ) ) {
            return;
        }

        $nonce = isset( $_GET[ '_wpnonce' ] ) ? sanitize_text_field( wp_unslash( (string) $_GET[ '_wpnonce' ] ) ) : '';
        if ( ! wp_verify_nonce( $nonce, T4A_PREFIX . '_print_file' ) ) {
            return;
        }

        // phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotValidated -- values are sanitised on the same line via sanitize_file_name / sanitize_key ; each key is guarded by isset() below.
        if ( isset( $_GET[ T4A_PREFIX . "-type" ] ) && isset( $_GET[ T4A_PREFIX . "-file" ] ) ) {

            $filename = sanitize_file_name( wp_unslash( (string) $_GET[ T4A_PREFIX . "-file" ] ) );
            $type     = sanitize_key( wp_unslash( (string) $_GET[ T4A_PREFIX . '-type' ] ) );
            $link     = wp_nonce_url(
                add_query_arg(
                    [ T4A_PREFIX . '-type' => $type, T4A_PREFIX . '-file' => $filename, T4A_PREFIX . '-download' => '1' ],
                    get_admin_url()
                ),
                T4A_PREFIX . '_download_file'
            );

            $ext = pathinfo( $filename, PATHINFO_EXTENSION );

            if ( $ext === 'pdf' ) {
                FileServer::display_pdf( $filename, $type );
                die();
            }

            ob_start();
            ?>
            <!doctype html>
            <html>
            <head>
            </head>
            <body onload="window.print();">

            <img src="<?php echo esc_url( $link ); ?>">

            </body>
            </html>
            <?php
            ob_end_flush();
            die();
        }
        // phpcs:enable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized,WordPress.Security.ValidatedSanitizedInput.MissingUnslash,WordPress.Security.ValidatedSanitizedInput.InputNotValidated
    }
}
