<?php

declare( strict_types=1 );

namespace DocketConnector\GravityForms;

use GFCommon;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Abort if this file is called directly.
}

if ( ! class_exists( MetaBox::class ) ) {
	/**
	 * The Gravity Forms single entry meta box.
	 */
	class MetaBox {

		/** @var Invoice */
		private $invoice;

		/** @var string The name attribute for the button to send to Docket Invoice API. */
		private static $button_name_send_invoice = 'docket_invoice_send';

		/** @var array The Gravity Forms Form array. */
		private $form;

		/** @var array The Gravity Forms Entry array. */
		private $entry;

		/**
		 * MetaBox constructor.
		 */
		public function __construct() {
			$this->invoice = Invoice::get_instance();
		}

		/**
		 * Do the meta box callback on the single entry admin view screen.
		 *
		 * @see \DocketConnector\GravityForms\Setup::single_entry_add_docket_meta_box()
		 * @see \GFEntryDetail::lead_detail_page() Where do_meta_boxes() happens.
		 *
		 * @param array $args     An array containing the Form, Entry, and 'mode' key with a value like 'view'.
		 * @param array $meta_box This meta box's details, having this method as its callback.
		 */
		public function single_entry_add_docket_meta_box(
			array $args,
			array $meta_box
		): void {
			// Bail on something majorly wrong.
			if (
				empty( $args['entry'] )
				|| empty( $args['entry']['id'] )
				|| empty( $args['form'] )
				|| empty( $args['form']['id'] )
			) {
				return;
			}

			if ( ! GFCommon::current_user_can_any( 'gravityforms_edit_entry_notes' ) ) {
				return;
			}

			// Fix for the meta box heading icon to be next to meta box heading text instead of split.
			printf(
				'<style>#%s .postbox-header .hndle { 
					justify-content: flex-start;
					align-items: flex-start;
				 }</style>',
				$meta_box['id']
			);

			$this->form  = (array) $args['form'];
			$this->entry = (array) $args['entry'];

			$this->handle_invoice_button_clicked();

			$this->output_invoice_attempts();
			$this->output_invoice_button();
		}

		/**
		 * Get the Form ID as an integer, from the set class property.
		 *
		 * @return int
		 */
		private function get_form_id(): int {
			if ( empty( $this->form['id'] ) ) {
				return 0;
			}

			return (int) $this->form['id'];
		}

		/**
		 * Get the Entry ID as an integer, from the set class property.
		 *
		 * @return int
		 */
		private function get_entry_id(): int {
			if ( empty( $this->entry['id'] ) ) {
				return 0;
			}

			return (int) $this->entry['id'];
		}

		/**
		 * Display the message about the number of times this feed was attempted.
		 */
		private function output_invoice_attempts(): void {
			$entry_id = $this->get_entry_id();

			$attempts = $this->invoice->get_entry_meta_count_feed_attempts( $entry_id );

			if ( empty( $attempts ) ) {
				if ( $this->invoice->has_feed( $this->get_form_id() ) ) {
					echo '<p>';
					echo wp_kses_post(
						sprintf(
						// Translators: %s: name of the Gravity Forms Add-On.
							_x(
								'The %s feed has not previously attempted to send data for this this entry.</p>',
								'single Gravity Forms entry meta box',
								'docket-connector'
							),
							'<strong>' . $this->invoice->plugin_page_title() . '</strong>'
						)
					);
					echo '</p>';
				}

				return;
			}

			$successes = $this->invoice->get_entry_meta_count_feed_successes( $entry_id );
			$failures  = $this->invoice->get_entry_meta_count_feed_failures( $entry_id );

			$attempt_text = esc_html(
				sprintf(
					_nx(
						'%d time',
						'%d times',
						$attempts,
						'attempts to process Docket Invoice feed',
						'docket-connector'
					),
					number_format_i18n( $attempts )
				)
			);

			echo '<p>';

			echo wp_kses_post(
				sprintf(
				// Translators: %1$s: name of the Gravity Forms Add-On. %2$s time(s) attempted text. %3$s successes count. %4$s failures count.
					_x(
						'The %1$s feed attempted to send data for this entry to the Docket API %2$s: %3$s successful, %4$s unsuccessful.',
						'single Gravity Forms entry meta box count of attempts message',
						'docket-connector'
					),
					'<strong>' . $this->invoice->plugin_page_title() . '</strong>',
					$attempt_text,
					number_format_i18n( $successes ),
					number_format_i18n( $failures )
				)
			);

			echo '</p>';
		}

		/**
		 * Display the button to send this entry's data to the Docket Invoice API.
		 */
		private function output_invoice_button(): void {
			// Bail if no Invoice feed is setup.
			if ( ! $this->invoice->has_feed( $this->get_form_id() ) ) {
				return;
			}
			?>
			<div style="padding-top: 13px; border-top: 1px solid #ccd0d4;">
				<form method="post">
					<button
						type="submit"
						name="<?php echo esc_attr( self::$button_name_send_invoice ); ?>"
						value="1"
						class="button"
					>
						<span aria-hidden="true" style="position: relative; top: 5px;">
							<?php echo $this->invoice->get_docket_icon_for_settings( '19px' ); ?>
						</span>

						<?php echo esc_html_x(
							'Send to the Docket Invoice API',
							'single Gravity Forms entry meta box button',
							'docket-connector'
						); ?>
					</button>
					<?php wp_nonce_field( self::$button_name_send_invoice, self::$button_name_send_invoice . '_nonce' ); ?>
				</form>

				<p><i class="gficon-arrow-up gfield_required"></i>
					<?php
					echo wp_kses_post(
						sprintf(
						// Translators: %1$s: Opening <ul> tag. %2$s: Opening <li> tag. %3$s: Closing <li> tag. %4$s: Closing <ul> tag.
							_x(
								'Clicking this button will reload this screen and attempt to create a brand new invoice within Docket. There is no way to delete or update a Docket invoice from this plugin. Reasons you may want to click this button:
									%1$s
										%2$sIf this entry was created prior to implementing this Docket Invoice feed.%3$s
										%2$sIf the Docket Invoice feed was disabled at the time of this entry.%3$s
										%2$sIf this entry previously failed (such as if the Docket API was down or your server experienced an unrelated error), to retry.%3$s
										%2$sIf you changed the Docket Invoice feed field mapping settings, and the changes would alter the data sent to Docket.%3$s
										%2$sIf this entry previously failed, and you altered your settings to fix the issue, to retry.%3$s
										%2$sIf this entry was modified in a way that would alter the Docket invoice: first edit and save this entry, then click this button to send the modified data, then delete the previously-created invoice directly from within Docket.%3$s
										%2$sIf this entry was incorrectly determined to be SPAM, causing the Docket Invoice feed to be skipped.%3$s
									%4$s',
								'single Gravity Forms entry meta box button explanation',
								'docket-connector'
							),
							'<ul style="padding-left: 15px;">',
							'<li style="list-style-type: disc; margin-bottom: 0;">', // Override Gravity Forms' admin.css.
							'</li>',
							'</ul>'
						)
					);
					?>
				</p>
			</div>

			<?php
		}

		/**
		 * Handle the clicking of the button to send this entry's data to the Docket Invoice API.
		 *
		 * Adds 1-second page load delay after sending to Docket API to help get accurate count of number of attempts
		 * and successes, hopefully being unnoticeable to the end user. If the counts aren't right, just do a manual
		 * page refresh and numbers should be fully accurate by that time - but this is unnecessary in our testing.
		 */
		private function handle_invoice_button_clicked(): void {
			if ( ! self::is_an_invoice_button_click() ) {
				return;
			}

			// Will automatically print a "failed" page and die if appropriate, else we'll continue;
			check_admin_referer( self::$button_name_send_invoice, self::$button_name_send_invoice . '_nonce' );

			$this->invoice->maybe_process_feed( $this->entry, $this->form );
			sleep( 1 );
		}

		/**
		 * If is an invoice button click.
		 *
		 * @since 1.1.2
		 *
		 * @return bool
		 */
		public static function is_an_invoice_button_click(): bool {
			return
				isset( $_POST[ self::$button_name_send_invoice ] )
				&& 1 === (int) $_POST[ self::$button_name_send_invoice ];
		}

	}
}