<?php

namespace PostenBringCheckout\includes;

use PostenBringCheckout\admin\Backoffice;
use PostenBringCheckout\admin\log\FatalErrorLogger;
use PostenBringCheckout\checkout\integrations\shipmenttracking\ShipmentTrackingIntegration;
use PostenBringCheckout\checkout\integrations\vipps\VippsIntegration;
use PostenBringCheckout\checkout\PostenBringCheckoutPublic;
use PostenBringCheckout\checkout\store\CheckoutSchemaExtensions;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

/**
 * Main class
 *
 * Plugin main class responsible for connecting all the hooks
 *
 * @since 0.0.1
 */
class Main {
	/**
	 * Loader.
	 *
	 * @since 0.0.1
	 * @var Loader $loader Loader responsible for registering all actions and filters required
	 */
	protected $loader;
	/**
	 * Plugin name.
	 *
	 * @since 0.0.1
	 * @var string $plugin_name Plugin name
	 */
	protected $plugin_name;
	/**
	 * Plugin version.
	 *
	 * @since 0.0.1
	 * @var string $version Plugin version
	 */
	protected $version;

	/**
	 * Constructor
	 *
	 * Will prepare plugin state before hooks are registered
	 *
	 * @since 0.0.1
	 */
	public function __construct() {
		$this->plugin_name = 'posten-bring-checkout';
		$this->version     = POSTEN_BRING_CHECKOUT_VERSION;
		$this->load_environment_variables();
		$this->load_dependencies();
		$this->set_locale();
		$this->add_admin_hooks();
		$this->add_checkout_hooks();
		$this->add_integration_hooks();
		$this->register_schema_extensions();
		$this->register_fatal_error_logger();
	}

	/**
	 * Load dependencies
	 *
	 * This function will load the required dependencies and initialize the loader
	 *
	 * @since 0.0.1
	 */
	private function load_dependencies(): void {
		require_once plugin_dir_path( __DIR__ ) . 'includes/Loader.php';
		require_once plugin_dir_path( __DIR__ ) . 'includes/I18n.php';
		require_once plugin_dir_path( __DIR__ ) . 'checkout/PostenBringCheckoutPublic.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/Backoffice.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/api/handlers/CredentialsHandler.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/api/handlers/BookingHandler.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/api/handlers/FeedbackHandler.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/api/handlers/RemoteLogApiHandler.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/api/handlers/SettingsHandler.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/api/models/MybringCustomerAndServices.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/api/models/MybringService.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/api/models/Order.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/api/models/OrderMapper.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/api/models/OrderItem.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/api/models/OrderRequest.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/api/models/OrderRequestDimensions.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/api/models/OrderRequestPackage.php';
		require_once plugin_dir_path( __DIR__ ) . 'checkout/block/CheckoutBlock.php';
		require_once plugin_dir_path( __DIR__ ) . 'checkout/block/CheckoutSummaryBlock.php';
		require_once plugin_dir_path( __DIR__ ) . 'checkout/block/CartBlock.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/bring/CredentialsService.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/bring/CheckoutApi.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/bring/models/Credentials.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/bring/models/address/Address.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/bring/models/address/AddressSuggestions.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/bring/models/booking/MybringBookingRequest.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/bring/models/booking/Consignment.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/bring/models/booking/Contact.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/bring/models/booking/Dimensions.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/bring/models/booking/EdiCustomsDeclaration.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/bring/models/booking/EdiCustomsDeclarationDetails.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/bring/models/booking/AdditionalService.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/bring/models/booking/MyBringBookingResponse.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/bring/models/booking/WebshopBookingMapper.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/bring/models/booking/Package.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/bring/models/booking/Parties.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/bring/models/booking/Party.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/bring/models/booking/PickupPoint.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/bring/models/booking/Product.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/bring/models/booking/WebshopBooking.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/bring/models/booking/CustomsDeclaration.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/bring/models/booking/CustomsInformation.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/bring/models/booking/CustomsNatureOfCargo.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/api/models/CredentialsVerificationResult.php';
		require_once plugin_dir_path( __DIR__ ) . 'checkout/store/CheckoutSchemaExtensions.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/bring/models/service/MaxCircumference.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/bring/models/service/MaxEdges.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/bring/models/service/MybringServiceDetails.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/bring/models/service/MaxDimensions.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/bring/models/booking/ValidationRequest.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/bring/models/booking/ValidationResponse.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/PostenBringImages.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/WeightUtils.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/log/RemoteLogHandler.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/log/FatalErrorLogger.php';
		require_once plugin_dir_path( __DIR__ ) . 'checkout/integrations/vipps/VippsIntegration.php';
		require_once plugin_dir_path( __DIR__ ) . 'checkout/integrations/shipmondo/ShipmondoIntegration.php';
		require_once plugin_dir_path( __DIR__ ) . 'checkout/integrations/shipmenttracking/ShipmentTrackingIntegration.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/bring/models/notification/Notifications.php';
		require_once plugin_dir_path( __DIR__ ) . 'checkout/integrations/dintero/DinteroIntegration.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/api/handlers/AddressHandler.php';
		require_once plugin_dir_path( __DIR__ ) . 'admin/api/handlers/CustomsHandler.php';

		if ( defined('WC_VERSION') && version_compare( WC_VERSION, '10.3.0', '>=' ) ) {
			require_once plugin_dir_path( __DIR__ ) . 'checkout/address/AddressProvider.php';
		}

		$this->loader = new Loader();
	}

	/**
	 * Load texts and translations
	 *
	 * This function will load the text domain and all translations
	 *
	 * @since 0.0.1
	 */
	private function set_locale(): void {
		$i18n = new I18n();
		$i18n->load_plugin_textdomain( $this->plugin_name );
	}

	/**
	 * Register fatal error handler
	 *
	 * This function will add a shutdown function that will log Posten Bring Checkout related fatal errors to a remote endpoint
	 *
	 * @since 0.0.1
	 */
	private function register_fatal_error_logger(): void {
		FatalErrorLogger::init();
	}

	/**
	 * Register store API extensions
	 *
	 * This function will register our store API extensions
	 *
	 * @since 0.0.1
	 */
	private function register_schema_extensions(): void {
		CheckoutSchemaExtensions::register();
	}

	/**
	 * Connect admin hooks
	 *
	 * This function will add all necessary admin callbacks to relevant hooks in the loader.
	 *
	 * @since 0.0.1
	 */
	private function add_admin_hooks(): void {
		$backoffice = new Backoffice( $this->get_plugin_name() );
		$this->loader->add_filter( 'plugin_action_links', $backoffice, 'add_plugin_links', 10, 2 );
		$this->loader->add_action( 'admin_menu', $backoffice, 'add_posten_bring_checkout_menu' );
		$this->loader->add_action( 'admin_enqueue_scripts', $backoffice, 'enqueue_scripts' );
		$this->loader->add_action( 'admin_enqueue_scripts', $backoffice, 'prefetch_order' );
		$this->loader->add_action( 'admin_enqueue_scripts', $backoffice, 'check_if_block_checkout_is_active' );
		$this->loader->add_action( 'rest_api_init', $backoffice, 'register_api_endpoints' );
		$this->loader->add_action( 'init', $backoffice, 'register_woo_onboarding_tasks' );
		$this->loader->add_action( 'woocommerce_shipping_init', $backoffice, 'register_posten_bring_shipping_options' );
		$this->loader->add_filter( 'woocommerce_shipping_methods', $backoffice, 'add_posten_bring_shipping_options' );
		$this->loader->add_filter( 'woocommerce_package_rates', $backoffice, 'sort_shipping_options', 10, 2 );
		$this->loader->add_filter( 'woocommerce_hidden_order_itemmeta', $backoffice, 'hide_shipping_method_meta_data' );
		$this->loader->add_action( 'woocommerce_admin_order_item_values', $backoffice, 'load_bring_section_on_order_details_meta', 10, 3 );
		$this->loader->add_filter( 'woocommerce_order_item_get_method_title', $backoffice, 'rename_shipping_option_on_details_page', 10, 2 );
		$this->loader->add_filter( 'woocommerce_validate_postcode', $backoffice, 'validate_postal_code', 10, 3 );
		$this->loader->add_filter( 'bulk_actions-woocommerce_page_wc-orders', $backoffice, 'posten_bring_checkout_add_bulk_action' );
		$this->loader->add_filter( 'bulk_actions-edit-shop_order', $backoffice, 'posten_bring_checkout_add_bulk_action' );
		$this->loader->add_action( 'admin_footer', $backoffice, 'add_massbooking_modal' );
		$this->loader->add_action( 'admin_footer', $backoffice, 'add_deactivate_modal' );
		$this->loader->add_filter( 'manage_woocommerce_page_wc-orders_columns', $backoffice, 'add_posten_bring_booking_status_column', 10, 1 );
		$this->loader->add_filter( 'manage_edit-shop_order_columns', $backoffice, 'add_posten_bring_booking_status_column', 10, 1 );
		$this->loader->add_action( 'manage_woocommerce_page_wc-orders_custom_column', $backoffice, 'add_posten_bring_booking_status_data', 10, 2 );
		$this->loader->add_action( 'manage_shop_order_posts_custom_column', $backoffice, 'add_posten_bring_booking_status_data', 10, 2 );
		$this->loader->add_action( 'woocommerce_product_options_general_product_data', $backoffice, 'add_custom_product_meta_data' );
		$this->loader->add_action( 'woocommerce_product_bulk_edit_end', $backoffice, 'add_custom_product_meta_data_bulk_edit' );
		$this->loader->add_action( 'woocommerce_process_product_meta', $backoffice, 'store_custom_product_meta_data' );
		$this->loader->add_action( 'woocommerce_product_bulk_edit_save', $backoffice, 'store_custom_product_meta_data_bulk_edit' );
		$this->loader->add_action( 'woocommerce_order_list_table_restrict_manage_orders', $backoffice, 'add_shipping_provider_filter', 10, 2 );
		$this->loader->add_action( 'woocommerce_store_api_checkout_order_processed', $backoffice, 'add_bring_as_shipping_company' );
		$this->loader->add_filter( 'woocommerce_order_list_table_prepare_items_query_args', $backoffice, 'apply_shipping_company_filter' );
		$this->loader->add_action( 'woocommerce_email_after_order_table', $backoffice, 'add_posten_block_to_email', 10, 4 );
		$this->loader->add_filter( 'woocommerce_register_log_handlers', $backoffice, 'add_posten_bring_checkout_log_handler' );
		$this->loader->add_action( 'woocommerce_variation_options', $backoffice, 'add_custom_product_variant_meta_data', 10, 3);
		$this->loader->add_action( 'woocommerce_save_product_variation', $backoffice, 'store_custom_product_variant_meta_data', 10, 2);
		$this->loader->add_action( 'admin_notices', $backoffice, 'add_warnings' );
		$this->loader->add_action( 'wp_ajax_posten_bring_checkout_dismiss_notice', $backoffice, 'dismiss_notice' );
		$this->loader->add_filter( 'dwc_shipping_icon', $backoffice, 'add_posten_bring_shipping_icon', 10, 3 );
		$this->loader->add_filter( 'load_textdomain_mofile', $backoffice, 'always_prefer_bundled_translations', 10, 2 );
	}

	/**
	 * Add checkout block
	 *
	 * This function will add all necessary public callbacks to relevant hooks in the loader.
	 *
	 * @since 0.0.1
	 */
	private function add_checkout_hooks(): void {
		$public = new PostenBringCheckoutPublic();
		$this->loader->add_action( 'woocommerce_blocks_checkout_block_registration', $public, 'register_posten_bring_checkout_block' );
		$this->loader->add_action( 'woocommerce_blocks_cart_block_registration', $public, 'register_posten_bring_cart_block' );
		$this->loader->add_action( 'block_categories_all', $public, 'register_posten_bring_checkout_block_category', 10, 2 );
		$this->loader->add_action( 'woocommerce_store_api_checkout_update_order_from_request', $public, 'register_order_meta_data_from_checkout_extension_data', 10, 2 );
		$this->loader->add_filter( '__experimental_woocommerce_blocks_add_data_attributes_to_block', $public, 'send_block_attributes_to_blocks' );
		$this->loader->add_action( 'woocommerce_after_shipping_rate', $public, 'add_pickup_point_selector_to_shortcode_checkout', 10, 2 );
		$this->loader->add_action( 'wp_enqueue_scripts', $public, 'add_pickup_point_selector_script' );
		$this->loader->add_action( 'woocommerce_checkout_create_order', $public, 'register_order_meta_data_from_shortcode_checkout', 10, 2 );
		$this->loader->add_action( 'woocommerce_after_checkout_validation', $public, 'validate_recipient_phone_number_and_address', 10, 2 );
		$this->loader->add_filter( 'woocommerce_checkout_fields', $public, 'set_phone_number_mandatory');
		$this->loader->add_action( 'woocommerce_checkout_update_order_review', $public, 'add_phone_number_prefix');
		$this->loader->add_filter( 'woocommerce_checkout_get_value', $public, 'get_phone_from_session', 10, 2);
		$this->loader->add_filter( 'woocommerce_update_order_review_fragments', $public,'refresh_billing_phone_fragment');
		$this->loader->add_filter( 'woocommerce_shipping_method_add_rate', $public, 'add_delivery_time_to_shipping_options', 10, 3);
		$this->loader->add_filter( 'woocommerce_cart_shipping_method_full_label', $public, 'display_free_when_shipping_is_free', 10, 2);
		$this->loader->add_filter( 'woocommerce_address_providers', $public, 'register_address_provider');
	}

	/**
	 * Add hooks provided by plugins we interact with
	 *
	 * This function will add all necessary callbacks to relevant hooks provided by other plugins in the loader.
	 *
	 * @since 0.0.1
	 */
	private function add_integration_hooks(): void {
		$vipps = new VippsIntegration();
		$shipment_tracking = new ShipmentTrackingIntegration();
		$this->loader->add_filter( 'woo_vipps_shipping_method_pickup_points', $vipps, 'add_pickup_points_to_vipps', 10, 4);
		$this->loader->add_action( 'woo_vipps_set_order_shipping_details', $vipps, 'register_order_meta_data_from_vipps', 10, 3);
		$this->loader->add_filter( 'woo_vipps_checkout_json_shipping_methods', $vipps, 'remove_brand_from_title_in_vipps_checkout', 10, 2);
		$this->loader->add_filter( 'woo_vipps_shipping_method_description', $vipps, 'add_rate_description_to_vipps', 10, 3);
		$this->loader->add_filter( 'woo_vipps_shipping_method_timeslots', $vipps, 'add_home_delivery_alternatives_to_vipps', 10, 4);
		$this->loader->add_filter( 'woo_vipps_shipping_method_lead_time', $vipps, 'add_lead_time', 10, 4);
		$this->loader->add_filter( 'wc_shipment_tracking_get_providers', $shipment_tracking, 'add_custom_tracking_providers' );
	}

	/**
	 * Load all hooks
	 *
	 * This function will register all action and filter callbacks added to the loader
	 *
	 * @since 0.0.1
	 */
	public function run(): void {
		$this->loader->run();
	}

	/**
	 * Get plugin name
	 *
	 * Returns the name of the plugin
	 *
	 * @return string Plugin name.
	 * @since 0.0.1
	 */
	public function get_plugin_name(): string {
		return $this->plugin_name;
	}

	/**
	 * Get loader
	 *
	 * Returns the loader instance
	 *
	 * @return Loader Loader.
	 * @since 0.0.1
	 */
	public function get_loader(): Loader {
		return $this->loader;
	}

	/**
	 * Get plugin version
	 *
	 * Returns the version of the plugin
	 *
	 * @return string Plugin version.
	 * @since 0.0.1
	 */
	public function get_version(): string {
		return $this->version;
	}

	private function load_environment_variables() {
		$mybring_api_url = getenv( 'POSTEN_BRING_CHECKOUT_MYBRING_API_URL' );
		if ( ! $mybring_api_url && ! defined( 'POSTEN_BRING_CHECKOUT_MYBRING_API_URL' ) ) {
			define( 'POSTEN_BRING_CHECKOUT_MYBRING_API_URL', 'https://api.bring.com' );
		} elseif ( $mybring_api_url && ! defined( 'POSTEN_BRING_CHECKOUT_MYBRING_API_URL' ) ) {
			define( 'POSTEN_BRING_CHECKOUT_MYBRING_API_URL', $mybring_api_url );
		}
	}
}
