<?php

namespace Devikit\Wfirma\Frontend;

use Automattic\WooCommerce\Blocks\Integrations\IntegrationInterface;

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

/**
 * Class handling NIP field in WooCommerce Gutenberg blocks
 */
class CheckoutBlocks implements IntegrationInterface {

	/**
	 * Constructor
	 */
	public function __construct() {
		add_action( 'woocommerce_blocks_loaded', [ $this, 'init_blocks_integration' ] );

		// Bidirectional NIP meta sync - always active.
		add_action( 'added_user_meta', [ $this, 'on_nip_additional_meta_changed' ], 10, 4 );
		add_action( 'updated_user_meta', [ $this, 'on_nip_additional_meta_changed' ], 10, 4 );

		// Sync NIP before My Account edit-address is rendered.
		add_action( 'template_redirect', [ $this, 'sync_nip_before_my_account_display' ] );
	}

	/**
	 * Initialize blocks integration
	 */
	public function init_blocks_integration() {
		// Check if WooCommerce Blocks is available
		if ( ! class_exists( 'Automattic\WooCommerce\Blocks\Package' ) ) {
			return;
		}

		// Register integration with WooCommerce Blocks
		add_action( 'woocommerce_blocks_checkout_block_registration', [ $this, 'register_checkout_blocks_integration' ] );
		
		// Register additional checkout field for newer WooCommerce versions (8.8+)
		if ( function_exists( 'woocommerce_register_additional_checkout_field' ) &&
			 version_compare( WC_VERSION, '8.8.0', '>=' ) &&
			 $this->site_uses_block_checkout() ) {
			add_action( 'woocommerce_init', [ $this, 'register_additional_checkout_fields' ] );
			add_filter(
				'woocommerce_get_default_value_for_devikit-wfirma/billing_nip',
				[ $this, 'provide_default_nip_for_blocks_checkout' ],
				10,
				3
			);
		}
		
		// Store API hooks for validation and saving
		add_action( 'woocommerce_store_api_checkout_update_order_meta', [ $this, 'save_fields_from_blocks' ] );
		add_action( 'woocommerce_store_api_checkout_order_processed', [ $this, 'save_fields_from_blocks' ] );
		
		// Fallback for older versions
		add_action( 'woocommerce_checkout_order_processed', [ $this, 'save_fields_from_blocks_fallback' ], 10, 3 );
		
		// Copy NIP to standard format for compatibility
		add_action( 'woocommerce_checkout_order_processed', [ $this, 'copy_nip_to_standard_format' ], 20, 1 );
		add_action( 'woocommerce_store_api_checkout_order_processed', [ $this, 'copy_nip_to_standard_format' ], 20, 1 );
		
		// My Account integration for blocks (only if site uses blocks)
		if ( $this->site_uses_block_checkout() ) {
			// Remove classic NIP field from My Account when using blocks
			// WooCommerce 8.8+ automatically adds fields registered via woocommerce_register_additional_checkout_field to My Account
			add_filter( 'woocommerce_billing_fields', [ $this, 'remove_classic_nip_from_my_account' ], 999 );

			add_action( 'woocommerce_customer_save_address', [ $this, 'save_nip_field_my_account_blocks' ], 10, 2 );
			add_action( 'woocommerce_customer_save_address', [ $this, 'sync_wc_additional_field_to_billing_nip' ], 50, 2 );
		}
		
		// Add NIP to formatted billing address (HTML modification, like nip-field-for-woocommerce)
		// This avoids using {nip} placeholder system which causes issues in blocks checkout
		add_filter( 'woocommerce_order_get_formatted_billing_address', [ $this, 'add_nip_to_formatted_billing_address' ], 10, 3 );
	}

	/**
	 * Register checkout blocks integration
	 */
	public function register_checkout_blocks_integration( $registry ) {
		$registry->register( new self() );
	}

	/**
	 * The name of the integration.
	 *
	 * @return string
	 */
	public function get_name() {
		return 'devikit-wfirma-blocks';
	}

	/**
	 * When called invokes any initialization/setup for the integration.
	 */
	public function initialize() {
		// Register scripts and styles if needed
	}

	/**
	 * Returns an array of script handles to enqueue in the frontend context.
	 *
	 * @return string[]
	 */
	public function get_script_handles() {
		return [];
	}

	/**
	 * Returns an array of script handles to enqueue in the editor context.
	 *
	 * @return string[]
	 */
	public function get_editor_script_handles() {
		return [];
	}

	/**
	 * An array of key, value pairs of data made available to the block on the client side.
	 *
	 * @return array
	 */
	public function get_script_data() {
		return [];
	}

	/**
	 * Check if site uses block checkout
	 */
	private function site_uses_block_checkout() {
		$checkout_page_id = wc_get_page_id( 'checkout' );
		if ( ! $checkout_page_id ) {
			return false;
		}
		
		// Check if checkout page has blocks
		return has_block( 'woocommerce/checkout', $checkout_page_id );
	}

	/**
	 * Check if another NIP plugin is active
	 *
	 * @return bool
	 */
	private function is_other_nip_plugin_active() {
		// Include plugin.php if not already loaded
		if ( ! function_exists( 'is_plugin_active' ) ) {
			require_once ABSPATH . 'wp-admin/includes/plugin.php';
		}
		
		// Check for common NIP plugins
		$nip_plugins = [
			'woocommerce-nip-field/woocommerce-nip-field.php',
			'nip-field-woocommerce/nip-field-woocommerce.php',
			'nip-field-for-woocommerce/nip-field-for-woocommerce.php',
			'flexible-invoices-woocommerce/flexible-invoices-woocommerce.php',
			'woocommerce-ifirma/woocommerce-ifirma.php',
			'woocommerce-fakturownia/woocommerce-fakturownia.php',
			'invoicing-integration-for-infakt-and-woocommerce/invoicing-integration-for-infakt-and-woocommerce.php',
		];
		
		foreach ( $nip_plugins as $plugin ) {
			if ( is_plugin_active( $plugin ) ) {
				return true;
			}
		}
		
		return false;
	}

	/**
	 * Register additional checkout fields for blocks
	 * Note: Checkbox "Want Invoice" works ONLY on classic checkout, not in Gutenberg blocks
	 */
	public function register_additional_checkout_fields() {
		// Check if WooCommerce version supports this function
		if ( ! function_exists( 'woocommerce_register_additional_checkout_field' ) ) {
			return;
		}

		// If another NIP plugin is active, don't register our field
		if ( $this->is_other_nip_plugin_active() ) {
			return;
		}

		$settings = get_option( 'devikit_wfirma_settings', [] );
		$nip_required = isset( $settings['nip_required'] ) && $settings['nip_required'] === 'yes';
		$validate_format = isset( $settings['validate_nip_format'] ) && $settings['validate_nip_format'] === 'yes';
		
		// Prepare attributes for NIP field
		$attributes = [];
		if ( $validate_format ) {
			$attributes['pattern'] = '[0-9]{10}';
		}
		
		// Register NIP field - always visible in Gutenberg blocks
		try {
			woocommerce_register_additional_checkout_field(
				[
					'id'                => 'devikit-wfirma/billing_nip',
					'label'             => __( 'NIP', 'invoicing-integration-for-wfirma-and-woocommerce' ),
					'location'          => 'address',
					'type'              => 'text',
					'required'          => $nip_required,
					'index'             => 20, // After first name, before company field
					'attributes'        => $attributes,
					'sanitize_callback' => [ $this, 'sanitize_nip_field' ],
					'validate_callback' => [ $this, 'validate_nip_field' ],
				]
			);
		} catch ( \Exception $e ) {
			// Silently fail
		}
	}

	/**
	 * Sanitize NIP field
	 */
	public function sanitize_nip_field( $value ) {
		return sanitize_text_field( $value );
	}

	/**
	 * Validate NIP field
	 */
	public function validate_nip_field( $value, $errors ) {
		// If another NIP plugin is active, let it handle validation
		if ( $this->is_other_nip_plugin_active() ) {
			return;
		}
		
		$settings = get_option( 'devikit_wfirma_settings', [] );
		$nip_required = isset( $settings['nip_required'] ) && $settings['nip_required'] === 'yes';
		$validate_format = isset( $settings['validate_nip_format'] ) && $settings['validate_nip_format'] === 'yes';

		// If field is required and empty
		if ( $nip_required && empty( $value ) ) {
			$errors->add(
				'billing_nip_required',
				__( 'Pole NIP jest wymagane.', 'invoicing-integration-for-wfirma-and-woocommerce' )
			);
			return;
		}

		// Validate format if not empty
		if ( ! empty( $value ) && $validate_format ) {
			// Remove only spaces and dashes (allowed separators)
			$clean_nip = preg_replace( '/[\s\-]/', '', $value );
			
			// Check if contains ONLY digits and has exactly 10
			if ( ! preg_match( '/^[0-9]{10}$/', $clean_nip ) ) {
				$errors->add(
					'billing_nip_invalid',
					__( 'Numer NIP musi zawierać dokładnie 10 cyfr.', 'invoicing-integration-for-wfirma-and-woocommerce' )
				);
			}
		}
	}

	/**
	 * Save fields from blocks to order
	 */
	public function save_fields_from_blocks( $order ) {
		if ( ! $order ) {
			return;
		}

		// Save NIP field (only if another plugin didn't already save it)
		$existing_nip = $order->get_meta( '_billing_nip' );
		if ( empty( $existing_nip ) ) {
			$nip_value = $this->get_nip_value_from_request();
			if ( ! empty( $nip_value ) ) {
				$order->update_meta_data( '_billing_nip', sanitize_text_field( $nip_value ) );
			}
		}

		$order->save();
	}

	/**
	 * Get NIP value from various request sources
	 */
	private function get_nip_value_from_request() {
		$nip_value = '';
		
		// Check different possible data sources - only check specific keys, not entire $_POST
		// phpcs:disable WordPress.Security.NonceVerification.Missing -- This is called within WooCommerce checkout/order processing context
		if ( isset( $_POST['extensions']['devikit-wfirma']['billing_nip'] ) ) {
			$nip_value = sanitize_text_field( wp_unslash( $_POST['extensions']['devikit-wfirma']['billing_nip'] ) );
		} elseif ( isset( $_POST['billing_nip'] ) ) {
			$nip_value = sanitize_text_field( wp_unslash( $_POST['billing_nip'] ) );
		} elseif ( isset( $_POST['devikit-wfirma/billing_nip'] ) ) {
			$nip_value = sanitize_text_field( wp_unslash( $_POST['devikit-wfirma/billing_nip'] ) );
		} elseif ( isset( $_REQUEST['devikit-wfirma/billing_nip'] ) ) {
			// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Called by WooCommerce Blocks API which handles validation
			$nip_value = sanitize_text_field( wp_unslash( $_REQUEST['devikit-wfirma/billing_nip'] ) );
		}
		// phpcs:enable WordPress.Security.NonceVerification.Missing

		return $nip_value;
	}

	/**
	 * Save fields fallback for older versions
	 */
	public function save_fields_from_blocks_fallback( $order_id, $posted_data, $order ) {
		// Only proceed if this is from blocks checkout
		if ( ! $this->site_uses_block_checkout() ) {
			return;
		}

		if ( ! $order ) {
			return;
		}

		// Save NIP field (only if another plugin didn't already save it)
		$existing_nip = $order->get_meta( '_billing_nip' );
		if ( empty( $existing_nip ) ) {
			$nip_value = $this->get_nip_value_from_request();
			if ( ! empty( $nip_value ) ) {
				$order->update_meta_data( '_billing_nip', sanitize_text_field( $nip_value ) );
			}
		}
		
		$order->save();
	}

	/**
	 * Copy NIP from WooCommerce 8.8+ format to standard format for compatibility
	 */
	public function copy_nip_to_standard_format( $order ) {
		// Handle both order ID and order object
		if ( is_numeric( $order ) ) {
			$order = wc_get_order( $order );
		}
		
		if ( ! $order ) {
			return;
		}
		
		// Check if standard _billing_nip already exists and has value
		$existing_nip = $order->get_meta( '_billing_nip' );
		if ( ! empty( $existing_nip ) ) {
			return; // Already has standard format, no need to copy
		}
		
		// Try to get NIP from WooCommerce 8.8+ format (our plugin)
		$wc_nip_value = $order->get_meta( '_wc_billing/devikit-wfirma/billing_nip' );
		
		// Also try other plugin's format
		if ( empty( $wc_nip_value ) ) {
			$wc_nip_value = $order->get_meta( '_wc_billing/nip-field-wc/billing_nip' );
		}
		
		if ( ! empty( $wc_nip_value ) ) {
			// Copy to standard format for compatibility
			$order->update_meta_data( '_billing_nip', sanitize_text_field( $wc_nip_value ) );
			
			// Remove the blocks-specific meta to avoid duplicate rendering
			$order->delete_meta_data( '_wc_billing/devikit-wfirma/billing_nip' );
			$order->delete_meta_data( '_wc_billing/nip-field-wc/billing_nip' );
			
			$order->save();
		}
	}

	/**
	 * Remove classic NIP field from My Account when using blocks
	 * WooCommerce 8.8+ automatically adds fields registered via woocommerce_register_additional_checkout_field
	 */
	public function remove_classic_nip_from_my_account( $fields ) {
		// Only on My Account pages
		if ( is_account_page() && ! is_admin() ) {
			// Remove classic billing_nip field to prevent duplication
			if ( isset( $fields['billing_nip'] ) ) {
				unset( $fields['billing_nip'] );
			}
		}
		return $fields;
	}

	/**
	 * Save NIP field in My Account address form (blocks system)
	 */
	public function save_nip_field_my_account_blocks( $user_id, $load_address ) {
		if ( $load_address !== 'billing' ) {
			return;
		}

		if ( $this->is_other_nip_plugin_active() ) {
			return;
		}

		$nip_value    = '';
		$field_in_post = false;

		// phpcs:disable WordPress.Security.NonceVerification.Missing -- WooCommerce My Account save address handles nonce
		$post_nip_keys = [
			'_wc_billing/devikit-wfirma/billing_nip',
			'devikit-wfirma/billing_nip',
		];
		foreach ( $post_nip_keys as $post_key ) {
			if ( isset( $_POST[ $post_key ] ) ) {
				$nip_value    = sanitize_text_field( wp_unslash( $_POST[ $post_key ] ) );
				$field_in_post = true;
				break;
			}
		}
		// phpcs:enable WordPress.Security.NonceVerification.Missing

		if ( empty( $nip_value ) ) {
			foreach ( [ '_wc_billing/devikit-wfirma/billing_nip', 'devikit-wfirma/billing_nip' ] as $meta_key ) {
				$val = (string) get_user_meta( $user_id, $meta_key, true );
				if ( ! empty( $val ) ) {
					$nip_value = $val;
					break;
				}
			}
		}

		if ( ! empty( $nip_value ) ) {
			update_user_meta( $user_id, 'billing_nip', $nip_value );
		} elseif ( $field_in_post ) {
			delete_user_meta( $user_id, 'billing_nip' );
		}
	}

	/**
	 * Bidirectional sync between billing_nip and WC 8.8+ additional-field meta keys.
	 */
	public function on_nip_additional_meta_changed( $meta_id, $user_id, $meta_key, $meta_value ) {
		$additional_keys = [
			'devikit-wfirma/billing_nip',
			'_wc_billing/devikit-wfirma/billing_nip',
			'nip-field-wc/billing_nip',
			'_wc_billing/nip-field-wc/billing_nip',
			'nip-field-woocommerce/billing_nip',
			'_wc_billing/nip-field-woocommerce/billing_nip',
		];

		$is_additional = in_array( $meta_key, $additional_keys, true );
		$is_canonical  = ( 'billing_nip' === $meta_key );

		if ( ! $is_additional && ! $is_canonical ) {
			return;
		}

		remove_action( 'added_user_meta', [ $this, 'on_nip_additional_meta_changed' ], 10 );
		remove_action( 'updated_user_meta', [ $this, 'on_nip_additional_meta_changed' ], 10 );

		$nip = sanitize_text_field( (string) $meta_value );

		if ( $is_additional ) {
			if ( ! empty( $nip ) ) {
				update_user_meta( $user_id, 'billing_nip', $nip );
				update_user_meta( $user_id, 'devikit-wfirma/billing_nip', $nip );
				update_user_meta( $user_id, '_wc_billing/devikit-wfirma/billing_nip', $nip );
			}
		} elseif ( $is_canonical ) {
			update_user_meta( $user_id, 'devikit-wfirma/billing_nip', $nip );
			update_user_meta( $user_id, '_wc_billing/devikit-wfirma/billing_nip', $nip );

			if ( $this->is_other_nip_plugin_active() ) {
				update_user_meta( $user_id, '_wc_billing/nip-field-wc/billing_nip', $nip );
				update_user_meta( $user_id, '_wc_billing/nip-field-woocommerce/billing_nip', $nip );
			}
		}

		add_action( 'added_user_meta', [ $this, 'on_nip_additional_meta_changed' ], 10, 4 );
		add_action( 'updated_user_meta', [ $this, 'on_nip_additional_meta_changed' ], 10, 4 );
	}

	/**
	 * Provide the billing NIP as a default value for the WC 8.8+ additional checkout field.
	 */
	public function provide_default_nip_for_blocks_checkout( $value, $group, $wc_object ) {
		if ( 'billing' !== $group ) {
			return $value;
		}

		if ( ! ( $wc_object instanceof \WC_Customer ) ) {
			return $value;
		}

		$user_id = $wc_object->get_id();
		if ( ! $user_id ) {
			return $value;
		}

		$candidates = [
			'billing_nip',
			'devikit-wfirma/billing_nip',
		];

		foreach ( $candidates as $key ) {
			$nip = (string) get_user_meta( $user_id, $key, true );
			if ( ! empty( $nip ) ) {
				update_user_meta( $user_id, '_wc_billing/devikit-wfirma/billing_nip', $nip );
				return $nip;
			}
		}

		return $value;
	}

	/**
	 * Sync NIP keys before the My Account edit-address page is rendered.
	 */
	public function sync_nip_before_my_account_display() {
		if ( ! is_account_page() || ! is_user_logged_in() ) {
			return;
		}

		$user_id     = get_current_user_id();
		$billing_nip = (string) get_user_meta( $user_id, 'billing_nip', true );
		$wc_nip      = (string) get_user_meta( $user_id, 'devikit-wfirma/billing_nip', true );
		$wc_nip_pref = (string) get_user_meta( $user_id, '_wc_billing/devikit-wfirma/billing_nip', true );

		$latest = ! empty( $wc_nip_pref ) ? $wc_nip_pref : ( ! empty( $wc_nip ) ? $wc_nip : $billing_nip );

		if ( $billing_nip === $latest && $wc_nip === $latest ) {
			return;
		}

		remove_action( 'added_user_meta', [ $this, 'on_nip_additional_meta_changed' ], 10 );
		remove_action( 'updated_user_meta', [ $this, 'on_nip_additional_meta_changed' ], 10 );

		update_user_meta( $user_id, 'billing_nip', $latest );
		update_user_meta( $user_id, 'devikit-wfirma/billing_nip', $latest );
		update_user_meta( $user_id, '_wc_billing/devikit-wfirma/billing_nip', $latest );

		add_action( 'added_user_meta', [ $this, 'on_nip_additional_meta_changed' ], 10, 4 );
		add_action( 'updated_user_meta', [ $this, 'on_nip_additional_meta_changed' ], 10, 4 );
	}

	/**
	 * Final NIP sync after WooCommerce saves My Account address (priority 50).
	 */
	public function sync_wc_additional_field_to_billing_nip( $user_id, $load_address ) {
		if ( $load_address !== 'billing' ) {
			return;
		}

		// phpcs:disable WordPress.Security.NonceVerification.Missing -- WooCommerce handles nonce before this hook fires
		$nip = '';

		$post_keys = [
			'_wc_billing/devikit-wfirma/billing_nip',
			'devikit-wfirma/billing_nip',
			'billing_nip',
		];
		foreach ( $post_keys as $key ) {
			if ( isset( $_POST[ $key ] ) && '' !== $_POST[ $key ] ) {
				$nip = sanitize_text_field( wp_unslash( $_POST[ $key ] ) );
				break;
			}
		}

		if ( empty( $nip ) ) {
			// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
			$raw_body = file_get_contents( 'php://input' );
			if ( ! empty( $raw_body ) ) {
				$body = json_decode( $raw_body, true );
				if ( is_array( $body ) ) {
					foreach ( [ '_wc_billing/devikit-wfirma/billing_nip', 'devikit-wfirma/billing_nip', 'billing_nip' ] as $key ) {
						if ( ! empty( $body[ $key ] ) ) {
							$nip = sanitize_text_field( $body[ $key ] );
							break;
						}
					}
				}
			}
		}
		// phpcs:enable WordPress.Security.NonceVerification.Missing

		if ( empty( $nip ) ) {
			$meta_keys = [
				'_wc_billing/devikit-wfirma/billing_nip',
				'devikit-wfirma/billing_nip',
				'_wc_billing/nip-field-wc/billing_nip',
				'nip-field-wc/billing_nip',
				'_wc_billing/nip-field-woocommerce/billing_nip',
				'nip-field-woocommerce/billing_nip',
				'billing_nip',
			];
			foreach ( $meta_keys as $key ) {
				$val = (string) get_user_meta( $user_id, $key, true );
				if ( ! empty( $val ) ) {
					$nip = sanitize_text_field( $val );
					break;
				}
			}
		}

		if ( ! empty( $nip ) ) {
			update_user_meta( $user_id, 'billing_nip', $nip );
			update_user_meta( $user_id, 'devikit-wfirma/billing_nip', $nip );
		}
	}

	/**
	 * Add NIP to formatted billing address (HTML modification)
	 * This method works like nip-field-for-woocommerce - modifies already formatted HTML address
	 * instead of using {nip} placeholder system which causes issues in blocks checkout
	 */
	public function add_nip_to_formatted_billing_address( $address, $raw_address, $order ) {
		// Only process on checkout page with blocks
		if ( ! is_checkout() || ! $this->site_uses_block_checkout() ) {
			return $address;
		}

		// Get NIP value
		$nip = '';
		if ( $order ) {
			$nip = $order->get_meta( '_billing_nip' );
			if ( empty( $nip ) ) {
				$nip = $order->get_meta( '_wc_billing/devikit-wfirma/billing_nip' );
			}
		}

		// If still empty, try to get from request/session (for blocks checkout during form filling)
		if ( empty( $nip ) ) {
			$nip = $this->get_nip_value_from_request();
		}

		// Check if NIP is already in the address to prevent duplication
		if ( ! empty( $nip ) && strpos( $address, 'NIP: ' . $nip ) === false && strpos( $address, 'NIP:' ) === false ) {
			// Remove any {nip} placeholder that might be there
			$address = preg_replace( '/\s*\{nip\}\s*/', '', $address );
			$address = preg_replace( '/\s*,\s*\{nip\}\s*/', '', $address );
			$address = preg_replace( '/\s*\{nip\}\s*,/', '', $address );
			$address = preg_replace( '/\s*&#123;nip&#125;\s*/', '', $address );
			
			// Add NIP before company name if exists
			if ( ! empty( $raw_address['company'] ) ) {
				$address = str_replace(
					$raw_address['company'],
					__( 'NIP', 'invoicing-integration-for-wfirma-and-woocommerce' ) . ': ' . esc_html( $nip ) . '<br>' . $raw_address['company'],
					$address
				);
			} else {
				// If no company name, add NIP at beginning of address
				$address = __( 'NIP', 'invoicing-integration-for-wfirma-and-woocommerce' ) . ': ' . esc_html( $nip ) . '<br>' . $address;
			}
		} else {
			// Even if NIP is empty, remove any {nip} placeholder that might be there
			$address = preg_replace( '/\s*\{nip\}\s*/', '', $address );
			$address = preg_replace( '/\s*,\s*\{nip\}\s*/', '', $address );
			$address = preg_replace( '/\s*\{nip\}\s*,/', '', $address );
			$address = preg_replace( '/\s*&#123;nip&#125;\s*/', '', $address );
			
			// Clean up any double commas or trailing commas
			$address = preg_replace( '/,\s*,/', ',', $address );
			$address = preg_replace( '/,\s*$/', '', $address );
			$address = trim( $address );
		}

		return $address;
	}
}
