<?php

namespace PaymentPage\RestAPI;

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

use PaymentPage\PostTypes\Form\FieldMap as PaymentPage_PostType_Form_FieldMap;
use WP_Error;
use WP_REST_Server;
use WP_REST_Request;
use PaymentPage\API\Notification as API_Notification;
use PaymentPage\API\PaymentPage as API_PaymentPage;
use PaymentPage\PaymentGateway as PaymentGateway;
use PaymentPage\Settings as Settings;
use PaymentPage\PostTypes\Form\FieldMap as FieldMap;
use PaymentPage\PaymentForm as PaymentPage_PaymentForm;
use PaymentPage\Email\ConfirmationEmail;
use PaymentPage\Model\Payments as PP_Model_Payments;

class Administration {

	public static function register_routes() {
		register_rest_route(
			PAYMENT_PAGE_REST_API_PREFIX . '/v1',
			'/administration/dashboard',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => '\PaymentPage\RestAPI\Administration::dashboard',
				'permission_callback' => function() {
					return current_user_can( PAYMENT_PAGE_ADMIN_CAP );
				},
			)
		);

		register_rest_route(
			PAYMENT_PAGE_REST_API_PREFIX . '/v1',
			'/administration/dismiss-notification',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => '\PaymentPage\RestAPI\Administration::dismiss_notification',
				'permission_callback' => function() {
					return current_user_can( PAYMENT_PAGE_ADMIN_CAP );
				},
			)
		);

		register_rest_route(
			PAYMENT_PAGE_REST_API_PREFIX . '/v1',
			'/administration/template-list',
			array(
				'methods'             => WP_REST_Server::READABLE,
				'callback'            => '\PaymentPage\RestAPI\Administration::template_list',
				'permission_callback' => function() {
					return current_user_can( PAYMENT_PAGE_ADMIN_CAP );
				},
			)
		);

		register_rest_route(
			PAYMENT_PAGE_REST_API_PREFIX . '/v1',
			'/administration/set-quick-setup-skip',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => '\PaymentPage\RestAPI\Administration::set_quick_setup_skip',
				'permission_callback' => function() {
					return current_user_can( PAYMENT_PAGE_ADMIN_CAP );
				},
			)
		);

		register_rest_route(
			PAYMENT_PAGE_REST_API_PREFIX . '/v1',
			'/administration/import-template',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => '\PaymentPage\RestAPI\Administration::import_template',
				'permission_callback' => function() {
					return current_user_can( PAYMENT_PAGE_ADMIN_CAP );
				},
			)
		);

    register_rest_route(
      PAYMENT_PAGE_REST_API_PREFIX . '/v1',
      '/administration/payment-forms/(?P<id>\d+)/builder-data',
      array(
        'methods'             => WP_REST_Server::READABLE,
        'callback'            => '\PaymentPage\RestAPI\Administration::payment_form_builder_data',
        'permission_callback' => function() {
          return current_user_can( PAYMENT_PAGE_ADMIN_CAP );
        },
      )
    );

    register_rest_route(
      PAYMENT_PAGE_REST_API_PREFIX . '/v1',
      '/administration/payment-forms/(?P<id>\d+)/live-preview',
      array(
        'methods'             => WP_REST_Server::ALLMETHODS,
        'callback'            => '\PaymentPage\RestAPI\Administration::payment_form_builder_live_preview',
        'permission_callback' => function() {
          return current_user_can( PAYMENT_PAGE_ADMIN_CAP );
        },
      )
    );

		register_rest_route(
			PAYMENT_PAGE_REST_API_PREFIX . '/v1',
			'/administration/payment-forms/(?P<id>\d+)/test-email',
			array(
				'methods'             => WP_REST_Server::CREATABLE,
				'callback'            => '\PaymentPage\RestAPI\Administration::payment_form_test_email',
				'permission_callback' => function() {
					return current_user_can( PAYMENT_PAGE_ADMIN_CAP );
				},
			)
		);
	}

	public static function dashboard( WP_REST_Request $request ) {
		return rest_ensure_response(
			array(
				'invalid_url_characters' => array( '~' ),
				'lang'                   => array(
					'upgrade'                             => __( 'Upgrade >', 'payment-page' ),
				/* translators: %1$s: payment method name, %2$s: upgrade link */
				'upgrade_payment_gateway'             => __( 'To accept %1$s, please %2$s', 'payment-page' ),
				/* translators: %1$s: payment gateway name, %2$s: upgrade link */
				'upgrade_payment_gateway_recurring'   => __( 'To accept recurring payments with %1$s, please %2$s', 'payment-page' ),

					'menu_name_payment_gateways'          => __( 'Payment Gateways', 'payment-page' ),
					'menu_name_templates'                 => __( 'Templates', 'payment-page' ),

					'payment_gateway_settings_set'        => __( 'Configure', 'payment-page' ),
					'payment_gateway_settings_edit'       => __( 'Configured', 'payment-page' ),
					/* translators: %s: payment gateway name */
				'payment_gateway_settings_title'      => __( '%s Connection Settings', 'payment-page' ),

				/* translators: %s: payment gateway name */
				'payment_gateway_connect'             => __( 'Connect with %s', 'payment-page' ),
				'payment_gateway_disconnect'          => __( 'Disconnect', 'payment-page' ),
					'payment_gateway_mode_test'           => __( 'Test', 'payment-page' ),
					'payment_gateway_mode_live'           => __( 'Live', 'payment-page' ),

					'payment_methods_title'               => __( 'Payment Methods', 'payment-page' ),
					'payment_methods_status'              => __( 'Status', 'payment-page' ),
					'payment_method_requires_https'       => __( 'This payment method requires a HTTPS connection for both live & testing', 'payment-page' ),
					'payment_method_settings_save'        => __( 'Save Settings', 'payment-page' ),

					'payment_gateway_methods_expand'      => __( 'Expand', 'payment-page' ),
					'payment_gateway_methods_hide'        => __( 'Hide', 'payment-page' ),
					'payment_gateway_webhook_settings_save' => __( 'Save Settings', 'payment-page' ),

					'template_notification_soon'          => __( 'More Coming Soon!', 'payment-page' ),
					'template_requires_elementor'         => __( 'Requires Elementor', 'payment-page' ),
					'template_install_elementor'          => __( 'Install Elementor Now', 'payment-page' ),
					'template_activate_elementor'         => __( 'Activate Elementor Now', 'payment-page' ),
					'template_select'                     => __( 'Import >', 'payment-page' ),
					'template_preview'                    => __( 'Preview >', 'payment-page' ),

				/* translators: %s: step name */
				'quick_setup_return'                  => __( '< %s', 'payment-page' ),
				/* translators: %s: next step name */
				'quick_setup_next'                    => __( 'Next, %s >', 'payment-page' ),
				/* translators: %s: step name */
				'quick_setup_skip_to'                 => __( 'Skip to %s >', 'payment-page' ),
					'quick_setup_exit'                    => __( 'Exit Quick Setup >', 'payment-page' ),
					'quick_setup_resume'                  => __( 'Start Quick Setup >', 'payment-page' ),

				/* translators: %1$s: invalid characters, %2$s: payment gateway name */
				'notification_url_invalid_characters' => __( 'Your website URL contains invalid character(s): %1$s which will cause problems with the %2$s connection.', 'payment-page' ),
				/* translators: %s: payment gateway name */
				'notification_url_mismatch_ssl'       => __( 'Your SSL security certificate is not properly configured on your site. Please configure SSL in order to connect %s. Your hosting provider can help with this.', 'payment-page' ),
				),
				'upgrade_link'           => admin_url( 'admin.php?page=payment-page-pricing' ),
				'template_list'          => self::_get_template_list(),
				'payment_gateway'        => PaymentGateway::get_administration_dashboard(),
				'quick_setup_skipped'    => intval( Settings::instance()->get( 'skipped_quick_setup' ) ),
				'quick_setup_steps'      => array(
					array(
						'alias'        => 'connect_payment_gateway',
						'title'        => __( 'Connect your Payment Gateway', 'payment-page' ),
						'sub_title'    => __( 'Welcome to Payment Page', 'payment-page' ),
						'nav_title'    => __( 'Manage Gateways', 'payment-page' ),
						'is_completed' => ( PaymentGateway::get_integration_from_settings( 'stripe' )->get_public_key() !== '' ),
						'template'     => 'payment-gateways',
					),
					array(
						'alias'          => 'connect_stripe_test_gateway',
						'title'          => __( 'Next, Connect Stripe in Test Mode', 'payment-page' ),
						'nav_title'      => __( 'Manage Gateways', 'payment-page' ),
						'is_completed'   => ( Settings::instance()->get( 'stripe_test_public_key' ) !== '' ),
						'requires_steps' => array( 0 ),
						'template'       => 'payment-gateways',
					),
					array(
						'alias'          => 'connect_stripe_live_gateway',
						'title'          => __( 'Next, Connect Stripe in Live Mode', 'payment-page' ),
						'nav_title'      => __( 'Manage Gateways', 'payment-page' ),
						'is_completed'   => ( Settings::instance()->get( 'stripe_live_public_key' ) !== '' ),
						'requires_steps' => array( 0, 1 ),
						'template'       => 'payment-gateways',
					),
					array(
						'alias'        => 'select_template',
						'title'        => __( 'Next, Select a Template', 'payment-page' ),
						'nav_title'    => __( 'Select a Template', 'payment-page' ),
						'is_completed' => 0, // ( intval( Settings::instance()->get( 'primary_template_page_id' ) ) != 0 ),
						'template'     => 'templates',
					),
				),
        'settings_base_url'      => admin_url( 'admin.php?page=payment-page' ),
        'additional_menu_points' => [
          [
            'title' => __('Payment Forms', 'payment-page'),
            'url'   => admin_url('edit.php?post_type=' . PAYMENT_PAGE_POST_TYPE_PAYMENT_FORM )
          ]
        ]
			)
		);
	}

	public static function dismiss_notification( WP_REST_Request $request ) {
		$latest_notification = API_Notification::instance()->get_latest_notification();

		if ( isset( $latest_notification['id'] ) ) {
			update_user_meta(
				get_current_user_id(),
				PAYMENT_PAGE_ALIAS . '_last_notification_id',
				$latest_notification['id']
			);
		}

		return rest_ensure_response(
			array(
				'status' => 'ok',
			)
		);
	}

	public static function template_list( WP_REST_Request $request ) {
		return rest_ensure_response(
			array(
				'data' => self::_get_template_list(),
			)
		);
	}

	public static function set_quick_setup_skip( WP_REST_Request $request ) {
		if ( ! $request->has_param( 'status' ) ) {
			return new WP_Error(
				'rest_error',
					/* translators: %s: request parameter name */
				esc_html( sprintf( __( 'Missing request param %s', 'payment-page' ), 'status' ) ),
				array(
					'status' => 400,
				)
			);
		}

		Settings::instance()->update(
			array(
				'skipped_quick_setup' => ( intval( $request->get_param( 'status' ) ) ? 1 : 0 ),
			)
		);

		return rest_ensure_response(
			array(
				'quick_setup_skipped' => intval( Settings::instance()->get( 'skipped_quick_setup' ) ),
			)
		);
	}

	private static function _get_template_list() {
		$template_list = API_PaymentPage::instance()->get_import_template_list();

		foreach ( $template_list as $template_key => $template ) {
			$template_list[ $template_key ]['user_can_install'] = intval( $template['user_can_install'] );

			if ( ! isset( $template['dependencies'] ) ) {
				continue;
			}

			foreach ( $template['dependencies'] as $dependency_key => $dependency ) {
				if ( ! is_array( $dependency ) || ! isset( $dependency['name'] ) || $dependency['name'] === 'gutenberg' ) {
					unset( $template['dependencies'][ $dependency_key ] );
					continue;
				}

				$plugin_slug = ( $dependency['name'] === 'elementor' ? 'elementor/elementor.php' : false );

				if ( $plugin_slug === false ) {
					unset( $template['dependencies'][ $dependency_key ] );
					continue;
				}

				if ( ! file_exists( WP_PLUGIN_DIR . '/' . $plugin_slug ) ) {
					$template['dependencies'][ $dependency_key ]['installed'] = 0;
					$template['dependencies'][ $dependency_key ]['activated'] = 0;
					continue;
				}

				$template['dependencies'][ $dependency_key ]['installed'] = 1;
				$template['dependencies'][ $dependency_key ]['activated'] = ( is_plugin_active( $plugin_slug ) ? 1 : 0 );
			}

			if ( empty( $template['dependencies'] ) ) {
				unset( $template_list[ $template_key ] );
				continue;
			}

			$template_list[ $template_key ] = $template;
		}

		return $template_list;
	}

	public static function import_template( WP_REST_Request $request ) {
		if ( ! $request->has_param( 'id' ) ) {
			return new WP_Error(
				'rest_error',
					/* translators: %s: request parameter name */
				esc_html( sprintf( __( 'Missing request param %s', 'payment-page' ), 'id' ) ),
				array(
					'status' => 400,
				)
			);
		}

		$template_id = (int) $request->get_param( 'id' );

		// Phase 31 — bundled templates use negative IDs and live inside the
		// plugin. Resolve those without a remote fetch.
		if ( $template_id < 0 ) {
			$bundled = \PaymentPage\Templates\BundledTemplates::instance()->find_by_id( $template_id );
			if ( ! is_array( $bundled ) ) {
				return new WP_Error(
					'rest_error',
					__( 'Bundled template not found.', 'payment-page' ),
					array( 'status' => 404 )
				);
			}
			$template_information = array(
				'content'  => array( 'rendered' => '' ),
				'metadata' => array(
					'payment_page_settings' => $bundled['settings'] ?? array(),
				),
			);
		} else {
			$template_information = API_PaymentPage::instance()->get_import_template_content( $template_id );
		}

		if ( empty( $template_information ) ) {
			return new WP_Error(
				'rest_error',
				__( 'Could not retrieve template, please try again.', 'payment-page' ),
				array(
					'status' => 400,
				)
			);
		}

		unset( $template_information['metadata']['_edit_last'] );
		unset( $template_information['metadata']['_edit_lock'] );
		unset( $template_information['metadata']['_wp_old_slug'] );
		unset( $template_information['metadata']['is_template'] );
		unset( $template_information['metadata']['_is_template'] );

		if ( intval( Settings::instance()->get( 'primary_template_page_id' ) ) != 0 ) {
			wp_update_post(
				array(
					'ID'           => Settings::instance()->get( 'primary_template_page_id' ),
					'post_content' => $template_information['content']['rendered'],
				)
			);

			$page_id = Settings::instance()->get( 'primary_template_page_id' );

			Settings::instance()->update(
				array(
					'primary_template_import_id' => intval( $request->get_param( 'id' ) ),
				)
			);
		} else {
			$page_id = wp_insert_post(
				array(
					'post_title'   => PAYMENT_PAGE_NAME,
					'post_content' => $template_information['content']['rendered'],
					'post_status'  => 'draft',
					'post_author'  => 1,
					'post_type'    => 'page',
				)
			);

			Settings::instance()->update(
				array(
					'primary_template_page_id'   => $page_id,
					'primary_template_import_id' => intval( $request->get_param( 'id' ) ),
				)
			);
		}

		// (Audit F003 / sc-7144) Template metadata is fetched from
		// paymentpageplugin.com/wp-json/wp/v2/pages/{id} (see API/PaymentPage::get_import_template_content).
		// The previous implementation passed each meta_value through maybe_unserialize() which
		// is a textbook PHP Object Injection / RCE vector — if the platform API server is ever
		// compromised, a single malicious template payload becomes RCE-on-every-WP-site (~1000
		// active installs) via well-known POP-chains (WordPress core, WooCommerce, Elementor,
		// Yoast, Action Scheduler all ship gadget classes).
		//
		// 1.5.0: JSON-only round-trip. Anything that arrives as a serialized PHP string is
		// rejected. Scalars and JSON-decodable arrays pass through; add_post_meta() handles
		// its own serialization for arrays.
		foreach ( $template_information['metadata'] as $meta_key => $meta_values ) {
			delete_post_meta( $page_id, $meta_key );

			foreach ( $meta_values as $meta_value ) {
				$meta_value = self::_sanitize_template_meta_value( $meta_value );

				if ( $meta_value === null ) {
					continue;
				}

				if ( is_string( $meta_value ) ) {
					$meta_value = addslashes( $meta_value );
				}

				add_post_meta( $page_id, $meta_key, $meta_value );
			}
		}

		return rest_ensure_response(
			array(
				/* translators: %s: edit page link */
			'message' => sprintf( __( 'Import Success, %s', 'payment-page' ), '<a href="' . admin_url( 'post.php?post=' . $page_id . '&action=elementor' ) . '" target="_blank">' . __( 'Edit Page', 'payment-page' ) . '</a>' ),

			)
		);
	}

  public static function payment_form_builder_data( WP_REST_Request $request ) {
    return [
      'sections'        => [
        [
          'title' => __( "General", 'payment-page' ),
          'alias' => 'content',
        ],
        [
          'title' => __( "Style", 'payment-page' ),
          'alias' => 'style',
        ]
      ],
      'field_groups'    => FieldMap::get_field_groups_with_values(intval($request->get_param('id'))),
      'field_namespace' => 'payment_page_settings',
      'live_preview_endpoint' => PAYMENT_PAGE_REST_API_PREFIX . '/v1/administration/payment-forms/' . intval($request->get_param('id')) . '/live-preview'
    ];
  }

  public static function payment_form_builder_live_preview( WP_REST_Request $request ) {
    header( 'Content-Type: text/html' );

    $post_id = intval($request->get_param('id'));
    $settings = PaymentPage_PostType_Form_FieldMap::get_form_settings_mapped_as_key_value($post_id);

    if($request->has_param('payment_page_settings')) {
      $payment_page_settings = $request->get_param('payment_page_settings');
      $payment_page_settings = payment_page_administration_process_request_payment_page_settings( $payment_page_settings );

      foreach( $payment_page_settings as $k => $v )
        $settings[ $k ] = $v;
    }

    $settings[ 'is_live_preview' ] = 1;

    echo PaymentPage_PaymentForm::instance()->get_from_settings($settings,$post_id); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Payment form HTML with inline CSS variables, escaped at render time in PaymentForm::get_from_settings()
    exit;
  }

	/**
	 * Send sample admin + payer emails using current form settings (Shortcut #6932).
	 */
	public static function payment_form_test_email( WP_REST_Request $request ) {
		$form_id = intval( $request->get_param( 'id' ) );

		if ( ! current_user_can( 'edit_post', $form_id ) ) {
			return new WP_Error(
				'rest_forbidden',
				__( 'Sorry, you are not allowed to edit this payment form.', 'payment-page' ),
				array( 'status' => 403 )
			);
		}

		$page_settings = get_post_meta( $form_id, 'payment_page_settings', true );

		if ( ! is_array( $page_settings ) || ! in_array( 'email', $page_settings['submit_actions'] ?? array(), true ) ) {
			return new WP_Error(
				'rest_invalid',
				__( 'Email action is not enabled for this form.', 'payment-page' ),
				array( 'status' => 400 )
			);
		}

		if ( ! isset( $page_settings['email_to'], $page_settings['email_subject_payer'], $page_settings['email_subject_admin'] ) ) {
			return new WP_Error(
				'rest_invalid',
				__( 'Email settings are incomplete.', 'payment-page' ),
				array( 'status' => 400 )
			);
		}

		$model = new PP_Model_Payments( array() );
		$model->post_id         = $form_id;
		$model->id              = 999001;
		$model->email_address   = wp_get_current_user()->user_email;
		$model->first_name      = 'Test';
		$model->last_name       = 'Customer';
		$model->payment_gateway = 'stripe';
		$model->payment_method  = 'ccard';
		$model->amount          = 1000;
		$model->amount_received = 1000;
		$model->currency        = 'usd';
		$model->is_live         = 0;
		$model->metadata_json   = array( 'frequency' => 'm_1' );
		$model->updated_at      = time();

		$request_data = array(
			'gateway'         => 'stripe',
			'method'          => 'ccard',
			'mode'            => 'test',
			'name'            => $model->first_name . ' ' . $model->last_name,
			'email'           => $model->email_address,
			'amount'          => $model->amount,
			'amount_received' => $model->amount_received,
			'currency'        => $model->currency,
			'frequency'       => 'm_1',
		);

		if ( function_exists( '_payment_page_payment_identification_fields' ) ) {
			$request_data += _payment_page_payment_identification_fields( $form_id, intval( $model->id ) );
		}

		$headers = array( 'Content-Type: text/html; charset=UTF-8' );

		$from_header = ConfirmationEmail::build_from_header( $page_settings );
		if ( $from_header !== '' ) {
			$headers[] = $from_header;
		}

		$admin_body = ConfirmationEmail::build_body( 'admin', $page_settings, $model, $request_data );
		$payer_body = ConfirmationEmail::build_body( 'payer', $page_settings, $model, $request_data );

		if ( ConfirmationEmail::html_to_plaintext( $admin_body ) === '' || ConfirmationEmail::html_to_plaintext( $payer_body ) === '' ) {
			return new WP_Error(
				'rest_invalid',
				__( 'Generated email bodies were empty.', 'payment-page' ),
				array( 'status' => 500 )
			);
		}

		$ok_admin = true;
		foreach ( explode( ',', $page_settings['email_to'] ) as $email ) {
			$email = trim( $email );
			if ( $email === '' ) {
				continue;
			}
			$sent = ConfirmationEmail::with_plaintext_alt(
				$admin_body,
				static function () use ( $email, $page_settings, $headers, $admin_body ) {
					return wp_mail( $email, '[TEST] ' . $page_settings['email_subject_admin'], $admin_body, $headers );
				}
			);
			if ( ! $sent ) {
				$ok_admin = false;
			}
		}

		$ok_payer = ConfirmationEmail::with_plaintext_alt(
			$payer_body,
			static function () use ( $model, $page_settings, $headers, $payer_body ) {
				return wp_mail( $model->email_address, '[TEST] ' . $page_settings['email_subject_payer'], $payer_body, $headers );
			}
		);

		if ( ! $ok_admin || ! $ok_payer ) {
			return new WP_Error(
				'rest_invalid',
				__( 'WordPress could not send one or more test messages (check mail configuration).', 'payment-page' ),
				array( 'status' => 500 )
			);
		}

		return rest_ensure_response(
			array(
				'message' => __( 'Test emails sent.', 'payment-page' ),
			)
		);
	}

	/**
	 * Sanitizer for template metadata values arriving from the platform API.
	 * (Audit F003 / sc-7144)
	 *
	 * Returns scalar/array values safe for add_post_meta(); returns NULL for values that
	 * look like PHP-serialized strings (the dangerous shape — would have triggered
	 * Object Injection on the legacy maybe_unserialize() path).
	 *
	 * @param mixed $value
	 * @return mixed|null
	 */
	private static function _sanitize_template_meta_value( $value ) {
		// Arrays are passed through (add_post_meta handles serialization safely for arrays).
		if ( is_array( $value ) ) {
			return $value;
		}

		// Booleans, ints, floats, null all pass through.
		if ( ! is_string( $value ) ) {
			return $value;
		}

		// Reject anything that looks like a PHP-serialized payload (the RCE-class vector).
		// Standard PHP serialization prefixes: 'a:N:', 'O:N:', 'C:N:', 's:N:', 'i:', 'd:',
		// 'b:0;', 'b:1;', 'N;'. Reject all of them; legitimate template metadata from the
		// platform API is always plain text or arrays at this layer.
		if ( preg_match( '/^(?:a|O|C|s|i|d|b):|^N;/', $value ) === 1 ) {
			return null;
		}

		return $value;
	}

}
