<?php
/**
 * Plugin main class.
 *
 * @package InvoicesWooCommerce
 */

namespace WPDesk\FakturyKSEF;

use WPDesk\FakturyKSEF\AjaxResponse\AjaxResponse;
use WPDesk\FakturyKSEF\Api\AccessTokenService;
use WPDesk\FakturyKSEF\Api\APIClient;
use WPDesk\FakturyKSEF\Api\LowLevelAPIClient;
use WPDesk\FakturyKSEF\Api\Middleware\KsefRetryMiddleware;
use WPDesk\FakturyKSEF\Cron\ReconciliationJob;
use WPDesk\FakturyKSEF\Api\Repository\DocumentStateRepository;
use WPDesk\FakturyKSEF\Api\Services\AuthService;
use WPDesk\FakturyKSEF\Api\Services\CertificateService;
use WPDesk\FakturyKSEF\Api\Services\DocumentService;
use WPDesk\FakturyKSEF\Blocks\RegisterEditorBlocks;
use WPDesk\FakturyKSEF\Controller\DownloadXMLController;
use WPDesk\FakturyKSEF\Dashboard\SettingsTab;
use WPDesk\FakturyKSEF\Dashboard\VatRates;
use WPDesk\FakturyKSEF\Renderer\KSeFRenderer;
use WPDesk\FakturyKSEF\Repository\PluginSettings;
use WPDesk\FakturyKSEF\Services\DocumentKSeFSettings;
use WPDesk\FakturyKSEF\Services\DownloadXMLUrlGenerator;
use WPDesk\FakturyKSEF\Services\EncryptionService;
use WPDesk\FakturyKSEF\Services\InitialDataValidation;
use WPDesk\FakturyKSEF\Services\KSeFPreviewURLService;
use WPDesk\FakturyKSEF\Services\PageChecker;
use WPDesk\FakturyKSEF\Services\QRCodeService;
use WPDesk\FakturyKSEF\Services\ReconciliationCutOffDateService;
use WPDesk\FakturyKSEF\Services\RegisterQRCodeShortcode;
use WPDesk\FakturyKSEF\Services\XMLGeneratorService;
use WPDesk\FakturyKSEF\Xml\XmlFactory;
use WPDeskKSEFVendor\GuzzleHttp\Client;
use WPDeskKSEFVendor\GuzzleHttp\HandlerStack;
use WPDeskKSEFVendor\Psr\Log\LoggerAwareInterface;
use WPDeskKSEFVendor\Psr\Log\LoggerAwareTrait;
use WPDeskKSEFVendor\Psr\Log\NullLogger;
use WPDeskKSEFVendor\WPDesk\Logger\WPDeskLoggerFactory;
use WPDeskKSEFVendor\WPDesk\Notice\Notice;
use WPDeskKSEFVendor\WPDesk\Persistence\Adapter\WordPress\WordpressOptionsContainer;
use WPDeskKSEFVendor\WPDesk\PluginBuilder\Plugin\AbstractPlugin;
use WPDeskKSEFVendor\WPDesk\PluginBuilder\Plugin\HookableCollection;
use WPDeskKSEFVendor\WPDesk\PluginBuilder\Plugin\HookableParent;
use WPDeskKSEFVendor\WPDesk\View\Resolver\DirResolver;
use WPDeskKSEFVendor\WPDesk_Plugin_Info;


/**
 * Main plugin class. The most important flow decisions are made here.
 */
class Plugin extends AbstractPlugin implements LoggerAwareInterface, HookableCollection {

	use HookableParent;
	use LoggerAwareTrait;

	/**
	 * @var string
	 */
	private $script_version = '1.0';

	private ReconciliationCutOffDateService $cut_off_date_service;

	private PluginSettings $settings;

	/**
	 * @param WPDesk_Plugin_Info $plugin_info Plugin data.
	 */
	public function __construct( $plugin_info ) {
		$this->plugin_info = $plugin_info;
		parent::__construct( $this->plugin_info );
		$this->settings_url = admin_url( 'edit.php?post_type=inspire_invoice&page=ksef-settings' );
		$this->docs_url     = 'https://wpdesk.link/ksef-docs-pl';
		$this->support_url  = get_locale() === 'pl_PL' ? 'https://www.wpdesk.pl/support/' : 'https://flexibleinvoices.com/support/';
		$this->setLogger( $this->is_debug_mode() ? ( new WPDeskLoggerFactory() )->createWPDeskLogger() : new NullLogger() );
		$this->cut_off_date_service = new ReconciliationCutOffDateService();
	}

	/**
	 * Fires hooks
	 */
	public function hooks() {
		$this->settings     = new PluginSettings( new WordpressOptionsContainer( 'inspire_invoices_' ) );
		$reconciliation_job = new ReconciliationJob( $this->settings, $this->cut_off_date_service );
		$reconciliation_job->hooks();

		parent::hooks();

		add_filter( 'fi/core/ksef/should_display_menu', '__return_true', 99 );
		add_action( 'init', [ $this, 'init_plugin' ] );
	}

	public function init_plugin() {
		$requirement_checker = new RequirementChecker();

		if ( ! $requirement_checker->is_parent_plugin_active() ) {
			$this->show_missing_dependency_notice();
			return;
		}

		if ( ! $requirement_checker->is_parent_plugin_version_compatible() ) {
			$this->show_incompatible_version_notice();
			return;
		}

		$requirement_checker->create_aliases();

		$this->add_hookable( new RegisterEditorBlocks( $this->plugin_info ) );
		$this->cut_off_date_service->check_cut_off_date();

		add_action( 'fi/core/initialized', [ $this, 'initialize_ksef_services' ] );
	}

	public function initialize_ksef_services( $plugins_access ) {
		$token       = $this->settings->get_ksef_api_token();
		$company_nip = $this->settings->get_company_vat_number();

		$renderer    = $this->get_renderer();
		$environment = $this->settings->get_environment();

		$base_uri = $environment->get_host_url();

		$handler_stack = HandlerStack::create();
		$handler_stack->push( KsefRetryMiddleware::create(), KsefRetryMiddleware::MIDDLEWARE_NAME );

		$guzzle_client = new Client(
			[
				'base_uri' => $base_uri,
				'handler'  => $handler_stack,
				'timeout'  => 30.0,
				'headers'  => [
					'Content-Type' => 'application/json',
					'Accept'       => 'application/json',
				],
			]
		);

		$low_level_api                  = new LowLevelAPIClient( $guzzle_client, $this->logger );
		$encryption_service             = new EncryptionService();
		$token_service                  = new AccessTokenService();
		$document_ksef_state_repository = new DocumentStateRepository();
		$certificate_service            = new CertificateService( $low_level_api );
		$auth_service                   = new AuthService( $company_nip, $token, $low_level_api, $encryption_service, $token_service, $certificate_service );
		$api_client                     = new APIClient( $low_level_api, $auth_service );
		$document_service               = new DocumentService( $api_client, $encryption_service, $certificate_service );
		$ajax_response                  = new AjaxResponse();
		$ksef_url_preview_generator     = new KSeFPreviewURLService( $company_nip, $environment );
		$qr_code_generator              = new QRCodeService();
		$page_checker                   = new PageChecker();
		$download_xml_url_generator     = new DownloadXMLUrlGenerator();
		$ksef_document_settings         = new DocumentKSeFSettings( $this->settings );
		$initial_data_validator         = new InitialDataValidation( $this->settings );
		$xml_factory                    = new XmlFactory( $document_ksef_state_repository );
		$xml_generator                  = new XMLGeneratorService( $plugins_access, $this->settings, $ksef_document_settings, $initial_data_validator, $xml_factory );
		$vat_rates                      = new VatRates();

		$document_sender = new Xml\SendDocument( $this->settings, $renderer, $ajax_response, $document_service, $encryption_service, $document_ksef_state_repository, $xml_generator, $download_xml_url_generator );
		$this->add_hookable( $document_sender );

		$this->add_hookable( new DownloadXMLController( $xml_generator ) );
		$this->add_hookable( new Assets( $this->plugin_info, $page_checker, $this->settings ) );
		$this->add_hookable( new Dashboard\BulkAction( $this->plugin_info, $api_client ) );
		$this->add_hookable( new Dashboard\Columns( $renderer, $document_ksef_state_repository, $api_client ) );
		$this->add_hookable( new Dashboard\SettingsPageRegistry( new SettingsTab( $api_client, $renderer, $page_checker, $vat_rates ) ) );
		$this->add_hookable( new Dashboard\MetaBox( $renderer, $document_ksef_state_repository, $plugins_access, $api_client, $download_xml_url_generator, $ksef_document_settings ) );
		$this->add_hookable( new RegisterQRCodeShortcode( $renderer, $qr_code_generator, $ksef_url_preview_generator, $document_ksef_state_repository, $plugins_access ) );

		$this->hooks_on_hookable_objects();
	}

	private function show_missing_dependency_notice() {
		new Notice( esc_html__( '"Flexible Invoices KSeF" requires Flexible Invoice (Free or PRO) to be installed and activated. Please activate required plugin.', 'ksef-for-flexible-invoices' ), 'error', true );
	}

	private function show_incompatible_version_notice() {
		new Notice( esc_html__( '"Flexible Invoices KSeF" requires a newer version of Flexible Invoices. Please update the Flexible Invoices plugin.', 'ksef-for-flexible-invoices' ), 'error', true );
	}

	private function get_renderer(): KSeFRenderer {
		return new KSeFRenderer( new DirResolver( $this->plugin_info->get_plugin_dir() . '/templates' ) );
	}

	/**
	 * Returns true when debug mode is on.
	 *
	 * @return bool
	 */
	private function is_debug_mode(): bool {
		$helper_options = get_option( 'wpdesk_helper_options', [] );

		return isset( $helper_options['debug_log'] ) && '1' === $helper_options['debug_log'];
	}
}
