<?php
/**
 * WooCommerce PDF settings option management.
 *
 * @package PDFDraft_WooCommerce
 */

namespace PDFDraft\Woocommerce\Core;

use PDFDraft\Traits\Hooks;

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

/**
 * Manages PDF invoice settings stored as a WordPress option with REST API access.
 */
class PdfSettingsOption {

	use Hooks;

	/**
	 * Default WordPress option key for settings.
	 *
	 * @var string
	 */
	private const DEFAULT_OPTION_KEY = 'pdfdraft_pdf_invoices_for_woocommerce_settings';

	/**
	 * Register WordPress hooks for settings.
	 *
	 * @return void
	 */
	public function initHooks() {
		$this->addAction( 'rest_api_init', array( $this, 'registerRestRoute' ) );
	}

	/**
	 * Get the option key used for storing settings.
	 *
	 * @return string Option key.
	 */
	public function getOptionKey(): string {
		return (string) $this->applyFilters( 'pdfdraft_pdf_invoices_for_woocommerce_settings_option_key', self::DEFAULT_OPTION_KEY );
	}

	/**
	 * Get default settings values.
	 *
	 * @return array Default settings array.
	 */
	public function getDefaults(): array {
		$defaults = array(
			'general' => array(
				'invoice_settings' => array(
					'generation_mode'                => 'automatic',
					'disable_free_order_invoices'    => false,
					'invoice_number_mode'            => 'order_id',
					'invoice_number_start'           => 1,
					'show_my_account_download_button' => true,
					'invoice_prefix'                 => '',
					'invoice_suffix'                 => '',
					'storage_custom_folder'          => '',
					'storage_organize_by_date'       => false,
				),
			),
		);
		return (array) $this->applyFilters( 'pdfdraft_pdf_invoices_for_woocommerce_settings_defaults', $defaults );
	}

	/**
	 * Get the current settings merged with defaults.
	 *
	 * @return array Current settings.
	 */
	public function get(): array {
		$saved = get_option( $this->getOptionKey(), array() );
		if ( ! is_array( $saved ) ) {
			$saved = array();
		}
		return wp_parse_args( $saved, $this->getDefaults() );
	}

	/**
	 * Save settings to the database.
	 *
	 * @param array $settings Settings to save.
	 * @return void
	 */
	public function set( array $settings ): void {
		$current   = $this->get();
		$merged    = wp_parse_args( $settings, $current );
		$sanitized = $this->sanitize( $merged );
		$filtered  = (array) $this->applyFilters( 'pdfdraft_pdf_invoices_for_woocommerce_settings_before_save', $sanitized );
		update_option( $this->getOptionKey(), $filtered );
		$this->doAction( 'pdfdraft_pdf_invoices_for_woocommerce_settings_saved', $filtered );
	}

	/**
	 * Reset settings to their defaults.
	 *
	 * @return void
	 */
	public function reset(): void {
		$defaults = $this->getDefaults();
		update_option( $this->getOptionKey(), $defaults );
		$this->doAction( 'pdfdraft_pdf_invoices_for_woocommerce_settings_saved', $defaults );
	}

	/**
	 * Sanitize raw settings input.
	 *
	 * @param array $raw Raw settings array.
	 * @return array Sanitized settings.
	 */
	private function sanitize( array $raw ): array {
		$out = $raw;

		// Back-compat: map legacy flat key to nested structure if present.
		if ( isset( $raw['generation_mode'] ) && ! isset( $raw['general']['invoice_settings']['generation_mode'] ) ) {
			$out['general']['invoice_settings']['generation_mode'] = $raw['generation_mode'];
			unset( $out['generation_mode'] );
		}

		if ( isset( $out['general']['invoice_settings']['generation_mode'] ) ) {
			$mode = $out['general']['invoice_settings']['generation_mode'];
			$out['general']['invoice_settings']['generation_mode'] = in_array( $mode, array( 'automatic', 'manual' ), true )
				? $mode
				: 'automatic';
		}

		if ( isset( $out['general']['invoice_settings']['invoice_number_mode'] ) ) {
			$number_mode = $out['general']['invoice_settings']['invoice_number_mode'];
			$out['general']['invoice_settings']['invoice_number_mode'] = in_array( $number_mode, array( 'order_id', 'sequential' ), true )
				? $number_mode
				: 'order_id';
		}

		if ( isset( $out['general']['invoice_settings']['invoice_number_start'] ) ) {
			$start = absint( $out['general']['invoice_settings']['invoice_number_start'] );
			$out['general']['invoice_settings']['invoice_number_start'] = $start > 0 ? $start : 1;
		}

		if ( isset( $out['general']['invoice_settings']['show_my_account_download_button'] ) ) {
			$out['general']['invoice_settings']['show_my_account_download_button'] =
				(bool) $out['general']['invoice_settings']['show_my_account_download_button'];
		}

		if ( isset( $out['general']['invoice_settings']['invoice_prefix'] ) ) {
			$out['general']['invoice_settings']['invoice_prefix'] =
				sanitize_text_field( (string) $out['general']['invoice_settings']['invoice_prefix'] );
		}

		if ( isset( $out['general']['invoice_settings']['invoice_suffix'] ) ) {
			$out['general']['invoice_settings']['invoice_suffix'] =
				sanitize_text_field( (string) $out['general']['invoice_settings']['invoice_suffix'] );
		}

		if ( isset( $out['general']['invoice_settings']['storage_custom_folder'] ) ) {
			$raw = (string) $out['general']['invoice_settings']['storage_custom_folder'];
			// Strip path separators and sanitize to a safe folder name.
			$raw = str_replace( array( '\\', '..', "\0" ), '', $raw );
			$raw = trim( $raw, '/' );
			$out['general']['invoice_settings']['storage_custom_folder'] = sanitize_file_name( $raw );
		}

		if ( isset( $out['general']['invoice_settings']['disable_free_order_invoices'] ) ) {
			$out['general']['invoice_settings']['disable_free_order_invoices'] =
				(bool) $out['general']['invoice_settings']['disable_free_order_invoices'];
		}

		if ( isset( $out['general']['invoice_settings']['storage_organize_by_date'] ) ) {
			$out['general']['invoice_settings']['storage_organize_by_date'] =
				(bool) $out['general']['invoice_settings']['storage_organize_by_date'];
		}

		return wp_parse_args( $out, $this->getDefaults() );
	}

	/**
	 * Check REST API permission for settings access.
	 *
	 * @param \WP_REST_Request|null $request REST request object.
	 * @return bool True if the user has permission.
	 */
	public function permissionCallback( ?\WP_REST_Request $request = null ): bool {
		// Allow access if the user is a WooCommerce shop manager OR a WordPress
		// administrator.  manage_woocommerce may not be assigned on fresh installs
		// or in hosted trial environments (e.g. try.new / ZipWP) where WooCommerce
		// has not yet had a chance to apply its role/capability setup.
		$can = current_user_can( 'manage_woocommerce' ) || current_user_can( 'manage_options' );
		return (bool) $this->applyFilters( 'pdfdraft_pdf_invoices_for_woocommerce_settings_rest_permission', $can, $request );
	}

	/**
	 * Register REST API routes for settings.
	 *
	 * @return void
	 */
	public function registerRestRoute(): void {
		register_rest_route(
			'pdfdraft/v1',
			'/woocommerce/settings',
			array(
				'methods'             => 'GET',
				'permission_callback' => array( $this, 'permissionCallback' ),
				'callback'            => array( $this, 'restGet' ),
			)
		);
		register_rest_route(
			'pdfdraft/v1',
			'/woocommerce/settings',
			array(
				'methods'             => 'POST',
				'permission_callback' => array( $this, 'permissionCallback' ),
				'callback'            => array( $this, 'restUpdate' ),
			)
		);
	}

	/**
	 * Handle GET request for settings.
	 *
	 * @param \WP_REST_Request $request REST request object.
	 * @return \WP_REST_Response Settings response.
	 */
	public function restGet( \WP_REST_Request $request ): \WP_REST_Response {
		$settings = $this->get();
		$payload  = (array) $this->applyFilters( 'pdfdraft_pdf_invoices_for_woocommerce_settings_rest_response', $settings, $request );
		return rest_ensure_response( $payload );
	}

	/**
	 * Handle POST request to update settings.
	 *
	 * @param \WP_REST_Request $request REST request object.
	 * @return \WP_REST_Response Updated settings response.
	 */
	public function restUpdate( \WP_REST_Request $request ): \WP_REST_Response {
		$body = $request->get_json_params() ?: array();
		$this->set( $body );
		return $this->restGet( $request );
	}
}
