<?php

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

if ( ! class_exists( 'CMBIRD_Common_Functions' ) ) {
	/**
	 * Common functions for CommerceBird plugin integration with Zoho.
	 */
	class CMBIRD_Common_Functions {

		/**
		 * Detect whether a WooCommerce B2B plugin that owns the `wcb2b_group` CPT is active.
		 *
		 * Different distributions of "WooCommerce B2B" ship under different class names
		 * (`WooCommerceB2B`, `WooCommerce_B2B`, …) and the original `class_exists('WooCommerceB2B')`
		 * gate silently disabled every B2B price-list code path on installs that used a different name.
		 * The post-type registration is the actual contract we depend on, so detect by any signal.
		 *
		 * Must be called after the `init` action (post types are registered there).
		 *
		 * @return bool
		 */
		public static function is_wcb2b_active(): bool {
			static $active = null;
			if ( null !== $active ) {
				return $active;
			}
			$active = class_exists( 'WooCommerceB2B' )
				|| class_exists( 'WooCommerce_B2B' )
				|| function_exists( 'WCB2B' )
				|| defined( 'WCB2B_VERSION' )
				|| defined( 'WCB2B_PLUGIN_VERSION' )
				|| post_type_exists( 'wcb2b_group' );
			return $active;
		}

		/**
		 * Constructor.
		 */
		public function __construct() {
			add_action( 'woocommerce_thankyou', array( $this, 'cmbird_sync_frontend_order' ) );
			add_action( 'woocommerce_rest_insert_shop_order_object', array( $this, 'cmbird_on_insert_rest_api' ), 20, 3 );
			add_filter( 'wcs_renewal_order_created', array( $this, 'cmbird_zi_sync_renewal_order' ), 10, 2 );
			add_action( 'wp_ajax_zoho_admin_order_sync', array( $this, 'cmbird_zoho_order_sync' ) );
		}

		/**
		 * Sync order when it's created via the checkout.
		 *
		 * @param int $order_id The order ID.
		 * @return void
		 */
		public function cmbird_sync_frontend_order( $order_id ) {
			// return if the order is not coming via thank you page.
			if ( ! is_wc_endpoint_url( 'order-received' ) ) {
				return;
			}
			// Check if the transient flag is set.
			if ( get_transient( 'cmbird_thankyou_callback_executed_' . $order_id ) ) {
				return;
			}
			$zoho_inventory_access_token = get_option( 'cmbird_zoho_inventory_access_token' );
			// First sync the customer to Zoho Inventory if the access token is set.
			if ( is_string( $zoho_inventory_access_token ) && trim( $zoho_inventory_access_token ) !== '' ) {
				$zi_order_class = new CMBIRD_Order_Sync_ZI();
				$zi_order_class->cmbird_zi_sync_customer_checkout( $order_id );
				// Use WC Action Scheduler to sync the order to Zoho Inventory.
				$existing_schedule = as_has_scheduled_action( 'sync_zi_order', array( $order_id ) );
				if ( ! $existing_schedule ) {
					as_schedule_single_action( time(), 'sync_zi_order', array( $order_id ) );
					// Set the transient flag to prevent multiple executions.
					set_transient( 'cmbird_thankyou_callback_executed_' . $order_id, true, 60 );
				}
			}
			$zoho_crm_access_token = get_option( 'cmbird_zoho_crm_access_token' );
			// If the access token is set, sync the order to Zoho CRM.
			if ( is_string( $zoho_crm_access_token ) && trim( $zoho_crm_access_token ) !== '' ) {
				// Use WC Action Scheduler to sync the order to Zoho CRM.
				$existing_schedule = as_has_scheduled_action( 'sync_zcrm_order', array( $order_id ) );
				if ( ! $existing_schedule ) {
					as_schedule_single_action( time(), 'sync_zcrm_order', array( $order_id ) );
					// Set the transient flag to prevent multiple executions.
					set_transient( 'cmbird_thankyou_callback_executed_' . $order_id, true, 60 );
				}
			}
		}

		/**
		 * Sync order when its scheduled via the Action Scheduler.
		 *
		 * @return void
		 */
		public function cmbird_orders_prepare_sync() {
			$args     = func_get_args();
			$order_id = $args[0] ?? null;
			if ( get_option( 'cmbird_zoho_inventory_access_token' ) && $order_id ) {
				try {
					$zi_order_class = new CMBIRD_Order_Sync_ZI();
					$zi_order_class->zi_order_sync( $order_id );
				} catch ( \Throwable $e ) {
					error_log( 'Error in cmbird_orders_prepare_sync: ' . $e->getMessage() ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Required for security logging.
				}
			}
			if ( get_option( 'cmbird_zoho_crm_access_token' ) && $order_id ) {
				try {
					$zcrm_order_class = new CMBIRD_ZCRM_SalesOrder();
					$zcrm_order_class->cmbird_zcrm_order_sync( $order_id );
				} catch ( \Throwable $e ) {
					error_log( 'Error in cmbird_orders_prepare_sync: ' . $e->getMessage() ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Required for security logging.
				}
			}
		}

		/**
		 * Sync order when it's created via the WC API.
		 *
		 * @param WC_Data         $object Inserted object.
		 * @param WP_REST_Request $request Request object.
		 * @param boolean         $is_creating True when creating object, false when updating.
		 */
		public function cmbird_on_insert_rest_api( $object, $request, $is_creating ) {
			// $fd = fopen( __DIR__ . '/on_insert_rest_api.txt', 'w+' );
			$request_body       = $request->get_body();
			$request_body_array = json_decode( $request_body, true );
			// if the request body is empty or not an array, return early.
			if ( empty( $request_body_array ) || ! is_array( $request_body_array ) ) {
				return;
			}
			$order_status = $request_body_array['status'];
			$order_id     = $object->get_id();

			if ( get_option( 'cmbird_zoho_inventory_access_token' ) ) {
				$zi_order_class = new CMBIRD_Order_Sync_ZI();
				// Check how many keys there are in the request body array. If there are only two keys then we don't need to do anything.
				if ( count( $request_body_array ) === 2 && null !== $request_body_array ) {
					if ( in_array( $order_status, array( 'cancelled', 'wc-merged' ) ) ) {
						$zi_order_class->salesorder_void( $order_id );
					}
				} else {
					$zi_order_class->zi_order_sync( $order_id );
				}
			}
			// same for Zoho CRM.
			if ( get_option( 'cmbird_zoho_crm_access_token' ) ) {
				$zcrm_order_class = new CMBIRD_ZCRM_SalesOrder();
				// Check how many keys there are in the request body array. If there are only two keys then we don't need to do anything.
				if ( count( $request_body_array ) === 2 && null !== $request_body_array ) {
					return;
				} else {
					$zcrm_order_class->cmbird_zcrm_order_sync( $order_id );
				}
			}

			// fclose($fd);
		}

		/**
		 * Sync Renewal Order to Zoho once it's created.
		 *
		 * @param WC_Order        $renewal_order The renewal order object.
		 * @param WC_Subscription $subscription  The subscription object.
		 * @return WC_Order The renewal order object.
		 */
		public function cmbird_zi_sync_renewal_order( $renewal_order, $subscription ) {
			$order_id = $renewal_order->get_id();

			// Sync the order to Zoho CRM.
			if ( get_option( 'cmbird_zoho_crm_access_token' ) ) {
				$zcrm_order_class = new CMBIRD_ZCRM_SalesOrder();
				$zcrm_order_class->cmbird_zcrm_order_sync( $order_id );
			}

			// Sync the order to Zoho Inventory.
			if ( get_option( 'cmbird_zoho_inventory_access_token' ) ) {
				$zi_order_class = new CMBIRD_Order_Sync_ZI();
				$zi_order_class->zi_order_sync( $order_id );
			}

			return $renewal_order;
		}

		/**
		 * Sync a WooCommerce order to Zoho CRM and Zoho Inventory.
		 *
		 * Called via AJAX from the Zoho Order Sync admin page.
		 *
		 * @param int $order_id The order ID to sync.
		 *
		 * @return void
		 */
		public function cmbird_zoho_order_sync( $order_id ) {
			if ( ! $order_id && isset( $_POST['nonce'], $_POST['arg_order_data'] ) ) {
				if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'zoho_admin_order_sync' ) ) {
					wp_send_json_error( 'Nonce verification failed' );
				}
				$order_id = sanitize_text_field( wp_unslash( $_POST['arg_order_data'] ) );
			}

			if ( $order_id <= 0 ) {
				wp_send_json_error( 'Invalid order ID.' );
			}

			// Sync the order to Zoho CRM.
			if ( get_option( 'cmbird_zoho_crm_access_token' ) ) {
				$zcrm_order_class = new CMBIRD_ZCRM_SalesOrder();
				$zcrm_order_class->cmbird_zcrm_order_sync( $order_id );
			}

			// Sync the order to Zoho Inventory.
			if ( get_option( 'cmbird_zoho_inventory_access_token' ) ) {
				$zi_order_class = new CMBIRD_Order_Sync_ZI();
				$zi_order_class->zi_order_sync( $order_id );
			}

			wp_send_json_success( 'Order synced successfully.' );
		}

		/**
		 * Function to clear all orphan data.
		 */
		public function clear_orphan_data() {
			global $wpdb;
			// Delete orphaned product variations.
			$deleted_variations = absint(
				$wpdb->query(
					"DELETE products
					FROM {$wpdb->posts} products
					LEFT JOIN {$wpdb->posts} wp ON wp.ID = products.post_parent
					WHERE wp.ID IS NULL AND products.post_type = 'product_variation';"
				)
			);
			// Delete orphaned postmeta.
			$deleted_postmeta = absint(
				$wpdb->query(
					"DELETE pm
					FROM {$wpdb->postmeta} pm
					LEFT JOIN {$wpdb->posts} wp ON wp.ID = pm.post_id
					WHERE wp.ID IS NULL;"
				)
			);
			// Return the number of deleted entries (orphaned variations + orphaned postmeta).
			return $deleted_variations + $deleted_postmeta;
		}

		/**
		 * Get the tax class based on the tax percentage.
		 *
		 * @param float $percentage The tax percentage.
		 * @return string|false The tax class if found, or standard if not found.
		 */
		public function get_tax_class_by_percentage( $percentage ) {
			// $fd = fopen( __DIR__ . '/get_tax_class_by_percentage.txt', 'a+' );

			global $wpdb;
			// Determine the number of decimal places in the provided percentage.
			$decimal_places = strlen( substr( strrchr( $percentage, '.' ), 1 ) );

			// Round the percentage to the determined number of decimal places.
			$rounded_percentage = round( $percentage, $decimal_places );

			// Try to get from cache first.
			$cache_key = 'cmbird_tax_rate_' . md5( $rounded_percentage . '_' . $decimal_places );
			$tax_rates = wp_cache_get( $cache_key, 'commercebird' );

			if ( false === $tax_rates ) {
				$tax_rates = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}woocommerce_tax_rates WHERE ROUND(tax_rate, %d) = %f", $decimal_places, $rounded_percentage ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Cached above.
				wp_cache_set( $cache_key, $tax_rates, 'commercebird', HOUR_IN_SECONDS );
			}

			// If tax rates are found.
			if ( $tax_rates ) {
				// Get the tax class from the first matching tax rate.
				$tax_class = $tax_rates[0]->tax_rate_class;
				return $tax_class;
			} else {
				// Return null if no tax rates match the provided percentage.
				return 'standard';
			}
		}

		/**
		 * Get the WooCommerce tax class for a given Zoho tax ID using the configured mapping.
		 *
		 * @param string $zoho_tax_id The Zoho Inventory tax ID.
		 * @return string|null The WooCommerce tax_rate_class, or null if no mapping found.
		 */
		public function get_tax_class_by_zoho_id( $zoho_tax_id ) {
			if ( empty( $zoho_tax_id ) ) {
				return null;
			}

			$cache_key = 'cmbird_tax_class_zoho_' . md5( $zoho_tax_id );
			$cached    = wp_cache_get( $cache_key, 'commercebird' );

			if ( false !== $cached ) {
				return '' !== $cached ? $cached : null;
			}

			global $wpdb;

			// Find all configured Zoho→WC tax mappings.
			$mappings = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Cached above.
				$wpdb->prepare(
					"SELECT option_name, option_value FROM {$wpdb->options} WHERE option_name LIKE %s",
					'cmbird_zoho_inventory_tax_rate_%'
				)
			);

			$wc_tax_rate_id = null;
			foreach ( $mappings as $mapping ) {
				$parts = explode( '##', $mapping->option_value );
				if ( isset( $parts[0] ) && $parts[0] === $zoho_tax_id ) {
					$wc_tax_rate_id = substr( $mapping->option_name, strlen( 'cmbird_zoho_inventory_tax_rate_' ) );
					break;
				}
			}

			if ( null === $wc_tax_rate_id ) {
				wp_cache_set( $cache_key, '', 'commercebird', HOUR_IN_SECONDS );
				return null;
			}

			$rate = $wpdb->get_row( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Cached above.
				$wpdb->prepare(
					"SELECT tax_rate_class FROM {$wpdb->prefix}woocommerce_tax_rates WHERE tax_rate_id = %d",
					$wc_tax_rate_id
				)
			);

			$tax_class = $rate ? $rate->tax_rate_class : null;
			wp_cache_set( $cache_key, $tax_class ?? '', 'commercebird', HOUR_IN_SECONDS );

			return $tax_class;
		}

		/**
		 * Send email to admin.
		 *
		 * @param string $subject The subject of the email.
		 * @param string $message The message body of the email.
		 *
		 * @return void
		 */
		public function send_email( $subject, $message ) {
			$admin_email = get_option( 'admin_email' );
			$headers     = array( 'Content-Type: text/html; charset=UTF-8' );

			// Send the email.
			wp_mail( $admin_email, $subject, $message, $headers );
		}
	}
}
$cmbird_common_functions = new CMBIRD_Common_Functions();
