<?php
/**
 * Class ShippingMethodSimple
 *
 * @package WPDesk\FS\TableRate\
 */

namespace WPDesk\FS\TableRate;

use FSVendor\WPDesk\FS\TableRate\Logger\NoticeLogger;
use FSVendor\WPDesk\FS\TableRate\Logger\ShippingMethodLogger;
use FSVendor\WPDesk\FS\TableRate\Settings\MethodSettingsFactory;
use Psr\Log\LoggerInterface;
use WC_Shipping_Method;
use WPDesk\FS\TableRate\Rule\Condition\ConditionsFactory;
use WPDesk\FS\TableRate\Rule\Cost\RuleAdditionalCostFactory;
use WPDesk\FS\TableRate\Rule\Cost\RuleCostFieldsFactory;
use WPDesk\FS\TableRate\ShippingMethod\RateCalculatorFactory;
use WPDesk\FS\TableRate\ShippingMethod\SingleMethodSettings;
use WPDesk\FS\TableRate\Tax\TaxCalculator;
use WPDesk_Flexible_Shipping;

/**
 * Shipping method flexible_shipping_single
 */
class ShippingMethodSingle extends WC_Shipping_Method {

	const SHIPPING_METHOD_ID = 'flexible_shipping_single';

	/**
	 * Logger provided by Flexible Shipping plugin.
	 *
	 * @var LoggerInterface
	 */
	protected static $fs_logger;

	/**
	 * @var bool
	 */
	private $is_html_ads_loaded = false;

	/**
	 * ShippingMethodSingle constructor.
	 *
	 * @param int $instance_id .
	 */
	public function __construct( $instance_id = 0 ) {
		$this->instance_id = absint( $instance_id );

		$this->id = self::SHIPPING_METHOD_ID;
		$this->init();
	}

	/**
	 * Init.
	 */
	protected function init() {
		$this->supports = [
			'shipping-zones',
			'instance-settings',
		];
		$this->init_instance_form_fields( false );
		$this->method_title       = __( 'Flexible Shipping', 'flexible-shipping' );
		$this->method_description = __( 'A single Flexible Shipping method.', 'flexible-shipping' );
		if ( $this->instance_id ) {
			$docs_link = get_locale() === 'pl_PL' ? 'https://octol.io/fs-docs-pl' : 'https://octol.io/fs-docs';
			// Translators: docs link.
			$this->method_description = sprintf( __( 'A single Flexible Shipping method. Learn %1$show to configure FS shipping method &rarr;%2$s', 'flexible-shipping' ), '<a href="' . $docs_link . '" target="_blank">', '</a>' );
		}
		$this->title                      = $this->get_instance_option( 'method_title', $this->method_title );
		$this->instance_settings['title'] = $this->title;
		$this->tax_status                 = $this->get_instance_option( 'tax_status' );
	}

	/**
	 * @param bool $with_integration_settings .
	 */
	public function init_instance_form_fields( $with_integration_settings = false ) {
		$this->instance_form_fields = ( new SingleMethodSettings() )->get_settings_fields( $this->instance_settings, $with_integration_settings );
	}

	/**
	 * @param array $form_fields .
	 * @param bool  $echo        .
	 *
	 * @return string
	 */
	public function generate_settings_html( $form_fields = [], $echo = true ) {
		$this->init_instance_form_fields( true );
		$form_fields = $this->get_instance_form_fields();
		if ( $echo ) {
			parent::generate_settings_html( $form_fields, $echo );
		} else {
			return parent::generate_settings_html( $form_fields, $echo );
		}
	}


	/**
	 * Generate Title HTML.
	 *
	 * @param string $key  Field key.
	 * @param array  $data Field data.
	 *
	 * @return string
	 * @since  1.0.0
	 */
	public function generate_title_html( $key, $data ) {
		$field_key = $this->get_field_key( $key );
		$defaults  = [
			'title' => '',
			'class' => '',
		];

		$data = wp_parse_args( $data, $defaults );

		$ads = '';

		if ( ! $this->is_html_ads_loaded ) {
			ob_start();
			$shipping_method_id = self::SHIPPING_METHOD_ID;
			include __DIR__ . '/../../../../classes/table-rate/views/html-ads.php';
			$ads                      = ob_get_clean();
			$ads                      = apply_filters( 'flexible-shipping/sell-box', is_string( $ads ) ? $ads : '' );
			$this->is_html_ads_loaded = true;
		}

		ob_start();
		?>
		</table>
		<h3 class="wc-settings-sub-title <?php echo esc_attr( $data['class'] ); ?>"
			id="<?php echo esc_attr( $field_key ); ?>"><?php echo wp_kses_post( $data['title'] ); ?></h3>
		<?php if ( ! empty( $data['description'] ) ) : ?>
			<p><?php echo wp_kses_post( $data['description'] ); ?></p>
		<?php endif; ?>

		<?php echo wp_kses_post( $ads ); ?>

		<table class="form-table">
		<?php

		return ob_get_clean();
	}

	/**
	 * .
	 */
	public function init_instance_settings() {
		parent::init_instance_settings();
		if ( isset( $this->instance_settings['method_rules'] ) && ! is_array( $this->instance_settings['method_rules'] ) && is_string( $this->instance_settings['method_rules'] ) ) {
			$this->instance_settings['method_rules'] = json_decode( $this->instance_settings['method_rules'], true );
		}
		$this->instance_settings['id_for_shipping'] = $this->get_rate_id();
		$this->instance_settings['title']           = $this->title;
	}

	/**
	 * @return bool
	 */
	public function process_admin_options() {
		$this->init_instance_form_fields( true );
		$filter_name     = 'woocommerce_shipping_' . $this->id . '_instance_settings_values';
		$filter_callback = [ $this, 'process_integrations_settings' ];
		add_filter( $filter_name, $filter_callback );
		$processed = parent::process_admin_options();
		remove_filter( $filter_name, $filter_callback );

		return $processed;
	}

	/**
	 * @param array $settings .
	 *
	 * @return array
	 */
	public function process_integrations_settings( $settings ) {
		$settings = apply_filters( 'flexible_shipping_process_admin_options', $settings );

		return $settings;
	}

	/**
	 * Admin options.
	 */
	public function admin_options() {
		parent::admin_options();
		do_action( 'flexible_shipping_method_script', self::SHIPPING_METHOD_ID, $this->instance_id );
	}

	/**
	 * Renders shipping rules settings.
	 *
	 * @param string $key  .
	 * @param array  $data .
	 *
	 * @return string
	 */
	public function generate_shipping_rules_html( $key, $data ) {
		$field_key             = $this->get_field_key( $key );
		$method_rules_settings = $this->get_option( $key, '[]' );
		$rules_settings        = new RulesSettingsField( $field_key, $field_key, $data['title'], $data, ! is_array( $method_rules_settings ) ? json_decode( $method_rules_settings, true ) : $method_rules_settings );

		return $rules_settings->render();
	}

	/**
	 * @param string $key   .
	 * @param array  $value .
	 *
	 * @return string
	 */
	public function validate_shipping_rules_field( $key, $value ) {
		$rules_settings_processor = new Rule\Settings\SettingsProcessor(
			( null === $value || ! is_array( $value ) ) ? [] : $value,
			( new ConditionsFactory() )->get_conditions(),
			( new RuleCostFieldsFactory() )->get_fields(),
			( new Rule\Cost\RuleAdditionalCostFieldsFactory( ( new RuleAdditionalCostFactory() )->get_additional_costs() ) )->get_fields(),
			( new Rule\SpecialAction\SpecialActionFieldsFactory( ( new Rule\SpecialAction\SpecialActionFactory() )->get_special_actions() ) )->get_fields()
		);

		return json_encode( $rules_settings_processor->prepare_settings(), JSON_PRETTY_PRINT );
	}

	/**
	 * Field key.
	 * For compatibility with integrations scripts.
	 *
	 * @param string $key .
	 *
	 * @return string
	 */
	public function get_field_key( $key ) {
		return $this->plugin_id . WPDesk_Flexible_Shipping::METHOD_ID . '_' . $key;
	}

	/**
	 * Get method rules.
	 *
	 * @return array
	 */
	public function get_method_rules() {
		return $this->get_instance_option( 'method_rules', [] );
	}

	/**
	 * @param string $key   .
	 * @param string $value .
	 *
	 * @return bool
	 */
	public function update_instance_option( $key, $value = '' ) {
		if ( empty( $this->instance_settings ) ) {
			$this->init_instance_settings();
		}

		$this->instance_settings[ $key ] = $value;

		return update_option( $this->get_instance_option_key(), apply_filters( 'woocommerce_shipping_' . $this->id . '_instance_settings_values', $this->instance_settings, $this ), 'yes' );
	}

	/**
	 * @param array $package .
	 */
	public function calculate_shipping( $package = [] ) {
		$rate_calculator = RateCalculatorFactory::create_for_shipping_method( $this, $package );

		$method_settings = MethodSettingsFactory::create_from_array( $this->instance_settings );

		$logger = $this->prepare_shipping_method_calculation_logger( $method_settings );

		$rate_calculator->set_logger( $logger );
		$calculated_rate = $rate_calculator->calculate_rate( $method_settings, $this->get_rate_id(), is_user_logged_in() );

		if ( ! empty( $calculated_rate ) && $this->should_add_rate( $calculated_rate ) ) {
			$calculated_rate = ( new TaxCalculator( $method_settings, \WC_Tax::get_shipping_tax_rates() ) )->append_taxes_to_rate_if_enabled( $calculated_rate, WC()->cart->get_customer()->get_is_vat_exempt() );
			$this->add_rate( $calculated_rate );
			$logger->debug( __( 'Shipping cost added.', 'flexible-shipping' ), $logger->get_results_context() );
		}

		$logger->show_notice_if_enabled();
	}

	/**
	 * @param array $calculated_rate .
	 *
	 * @return bool
	 */
	private function should_add_rate( array $calculated_rate ) {
		return ! ( 'yes' === $this->get_instance_option( 'method_visibility', 'no' ) && ! is_user_logged_in() );
	}

	/**
	 * Set logger. This logger is set by Flexible Shipping plugin.
	 *
	 * @param LoggerInterface $fs_logger .
	 */
	public static function set_fs_logger( LoggerInterface $fs_logger ) {
		static::$fs_logger = $fs_logger;
	}

	/**
	 * @param \FSVendor\WPDesk\FS\TableRate\Settings\MethodSettings $shipping_method_settings .
	 *
	 * @return Logger\ShippingMethodLogger
	 */
	private function prepare_shipping_method_calculation_logger( $shipping_method_settings ) {
		$method_debug_mode     = $shipping_method_settings->get_debug_mode();
		$shipping_method_title = $shipping_method_settings->get_title();
		$shipping_method_url   = admin_url(
			'admin.php?page=wc-settings&tab=shipping&instance_id=' . sanitize_key( $this->instance_id ) . '&action=edit&method_id=' . sanitize_key( $shipping_method_settings->get_id() )
		);
		if ( null !== static::$fs_logger ) {
			$fs_logger = static::$fs_logger;
		} else {
			$fs_logger = NullLogger();
		}

		return new ShippingMethodLogger(
			$fs_logger,
			new NoticeLogger(
				$shipping_method_title,
				$shipping_method_url,
				'yes' === $method_debug_mode && current_user_can( 'manage_woocommerce' )
			)
		);
	}

}
