<?php

namespace WooPoPCozmosLabsPMS\Providers;

use WcElectronInvoice\Providers\OrdersProviderAbstract;
use function WcElectronInvoice\Functions\isCozmoslabsPaidMemberSubscriptionsActive;

defined( 'ABSPATH' ) || die( 'Not allowed.' );

class OrdersProvider extends OrdersProviderAbstract {

	/**
	 * @inheritDoc
	 */
	public function getOrders( $args = array(), $onlyCount = false ) {

		$payments = array();

		if ( isCozmoslabsPaidMemberSubscriptionsActive() ) {

			if ( empty( $args ) ) {
				$args = array(
					'status' => OrdersProviderAbstract::ORDERS_DEFAULT_LIST_STATUSES
				);
			}

			$args = $this->mapArgs( $args );

			// PMS order query extracts payments using only one status
			// so we need to query for each status separately
			// and merge the results
			foreach ( $args['status'] as $status ) {

				$newArgs           = $args;
				$newArgs['status'] = $status;
				$taxProvider       = new TaxesProvider();
				foreach ( \pms_get_payments( $newArgs ) as $index => $payment ) {
					$payments[] = new Order( $payment, $this, $taxProvider );
				}
			}
		}

		return $payments;
	}

	/**
	 * @inheritDoc
	 */
	public function getOrderSummaries( $args = array() ) {
		$summaries = array();

		foreach ( $this->getOrders( $args ) as $order ) {
			if ( ! $order ) {
				continue;
			}

			$summaries[] = $this->buildOrderSummary( $order );
		}

		return $summaries;
	}

	/**
	 * @param $orderId
	 */
	public function getOrder( $orderId ) {
		if ( isCozmoslabsPaidMemberSubscriptionsActive() ) {
			return new Order( pms_get_payment( $orderId ), $this, new TaxesProvider() );
		}

		return null;
	}

	/**
	 * @inheritDoc
	 */
	public function name() {
		return 'cozmoslabspms';
	}

	/**
	 * @inheritDoc
	 *
	 */
	public function get_label() {
		return __( 'CozmosLabs PMS', WC_EL_INV_TEXTDOMAIN );
	}

	/**
	 * @param $args
	 *
	 * @return array|mixed
	 */
	public function mapArgs( $args ) {

		// map the status to the ones used by WooCommerce
		if ( isset( $args['status'] ) ) {
			foreach ( $args['status'] as $key => $value ) {
				if ( $value == 'processing' ) {
					$args['status'][ $key ] = 'pending';
				}
			}
		}

		// map the date_created to date
		// date as array of dates, search for dates between the two dates
		// date as string, search for dates equal to the date
		if ( isset( $args['date_created'] ) ) {

			$dates = explode( '...', $args['date_created'] );
			foreach ( $dates as $key => $date ) {
				$dates[ $key ] = date( 'Y-m-d H:i:s', $date );
			}

			if ( sizeof( $dates ) < 2 ) {
				$dates = $dates[0];
			}

			unset( $args['date_created'] );
			$args['date'] = $dates;

		}

		return $args;
	}

	/**
	 * Save the tax rate and discount total in payment meta
	 * on payment insertx
	 *
	 * @param $payment_id
	 * @param $data
	 *
	 * @return void
	 */
	public function on_payment_insert( $payment_id, $data ) {

		if ( ! $payment_id ) {
			return;
		}

		// get the payment
		$payment = pms_get_payment( $payment_id );
		if ( ! $payment ) {
			return;
		}

		// get tax rates and save them in payment meta
		$taxSettings = TaxesProvider::get_tax_settings();
		if ( $taxSettings['enable_tax'] ) {

			$taxRate = isset( $taxSettings['default_tax_rate'] ) ? $taxSettings['default_tax_rate'] : 0;
			pms_update_payment_meta( $payment->id, 'pms_tax_rate', $taxRate );

		}


		// get the discount code and calculate the discount total based on type (percentage or fixed)
		// save it in payment meta
		$discount_code = isset( $_REQUEST['discount_code'] ) ? $_REQUEST['discount_code'] : '';
		if ( ! empty( $discount_code ) ) {
			$discount_code = pms_in_get_discount_by_code( $discount_code );
			if ( ! $discount_code ) {
				return;
			}

			$discount_type   = $discount_code->type;
			$discount_amount = $discount_code->amount;
			$discount_total  = $discount_type === 'percentage' ? $payment->total * $discount_amount / 100 : $discount_amount;
			pms_update_payment_meta( $payment->id, 'pms_discount_total', $discount_total );
		}

		// save the billing fields
		$this->pms_payment_save_form( $payment );

		$this->maybeCreateXmlOnCompletedPayment( $payment->id );

	}

	/**
	 * Save the tax rate and discount total in payment meta
	 * on payment update
	 *
	 * @param $payment
	 * @param $order
	 *
	 * @return mixed
	 */
	public function on_payment_admin_edit( $id, $data, $old_data ) {

		if ( ! $id ) {
			return;
		}

		$payment = pms_get_payment( $id );

		// get the discount code and
		// save the discount total in payment meta
		// calculate the discount total based on type (percentage or fixed)
		if ( ! empty( $payment->discount_code ) ) {
			$subscription    = pms_get_subscription_plan( $payment->subscription_id );
			$discount_code   = pms_in_get_discount_by_code( $payment->discount_code );
			$discount_type   = $discount_code->type;
			$discount_amount = $discount_code->amount;
			$discount_total  = $discount_type === 'percent' ? $subscription->price * $discount_amount / 100 : $discount_amount;
			pms_update_payment_meta( $payment->id, 'pms_discount_total', $discount_total );
		}

		// get tax rates and save them in payment meta
		$taxSettings = TaxesProvider::get_tax_settings();
		if ( $taxSettings['enable_tax'] ) {

			$taxRate = isset( $taxSettings['default_tax_rate'] ) ? $taxSettings['default_tax_rate'] : 0;
			pms_update_payment_meta( $payment->id, 'pms_tax_rate', $taxRate );

		}

		$orderProvider = $this->getOrder( $payment->id );
		if ( $orderProvider instanceof Order ) {
			\WcElectronInvoice\Functions\clearCachedDocumentAttachmentCache( $orderProvider, true );
		}

		$previousStatus = isset( $old_data['status'] ) ? (string) $old_data['status'] : '';
		$this->maybeCreateXmlOnCompletedPayment( $payment->id, $previousStatus );

	}

	/**
	 * Trigger XML saving only when the payment is in completed state.
	 *
	 * @param int         $paymentId
	 * @param string|null $previousStatus
	 *
	 * @return void
	 */
	private function maybeCreateXmlOnCompletedPayment( $paymentId, $previousStatus = null ) {
		if ( ! $paymentId ) {
			return;
		}

		$order = $this->getOrder( $paymentId );
		if ( ! $order instanceof Order ) {
			return;
		}

		$currentStatus = (string) $order->get_status();
		if ( 'completed' !== $currentStatus ) {
			return;
		}

		if ( null !== $previousStatus && 'completed' === $this->normalizePaymentStatus( $previousStatus ) ) {
			return;
		}

		\WcElectronInvoice\Xml\CreateXml::createXMLOnProviderOrderCompleted( $paymentId, $this->name() );
	}

	/**
	 * Normalize raw Cozmos payment statuses to POP provider statuses.
	 *
	 * @param string $status
	 *
	 * @return string
	 */
	private function normalizePaymentStatus( $status ) {
		switch ( (string) $status ) {
			case 'completed':
				return 'completed';
			case 'pending':
				return 'processing';
			case 'failed':
				return 'failed';
			case 'cancelled':
				return 'cancelled';
			case 'refunded':
				return 'refunded';
			default:
				return 'unknown';
		}
	}

	/**
	 * @param $payment
	 *
	 * @return void
	 */
	public function pms_payment_save_form( $payment = null ) {

		if ( is_null( $payment ) ) {
			return;
		}

		$fields_to_save = $this->admin_payment_billing_fields( $payment->id );

		foreach ( $fields_to_save as $key => $field ) {
			if ( ! array_key_exists( $key, $_REQUEST ) ) {
				continue;
			}

			$value = wp_unslash( $_REQUEST[ $key ] );
			$value = is_array( $value ) ? $value : sanitize_text_field( $value );
			pms_update_payment_meta( $payment->id, $key, $value );
		}

	}

	/**
	 * Add extra fields to the admin payment form
	 *
	 * @param $fields
	 *
	 * @return mixed
	 */
	public function tax_extra_fields( $tax_fields ) {

		// retrieve fields from WC billing fields
		/** @var $wcFields array * */
		$wcFields = apply_filters( 'wc_el_inv-billing_fields', array() );

		// @todo migliorare questo codice capendo il motivo per cui il filtro non torna i fields
		if ( empty( $wcFields ) ) {
			$wcFields = include_once \WcElectronInvoice\Plugin::getPluginDirPath( '/inc/billingFields.php' );
		}

		$wcFields = $this->mapWcFieldsToPMSFields( $wcFields );

		// Remove PMS default pms_vat_number field
		unset( $tax_fields['pms_vat_number'] );

		$tax_fields = array_merge( $tax_fields, $wcFields );

		return $tax_fields;
	}

	/**
	 * Add the extra fields to the admin payment form
	 *
	 * @param $payment
	 *
	 * @return void
	 */
	public function payment_edit_form_field( $payment = null ) {
		$payment_id = ! is_null( $payment ) ? $payment->id : 0;

		if ( ! $this->isPmsTaxEuVatEnabled() ) {
			echo '<div class="notice notice-warning inline pms-notice"><p>' .
			     esc_html__(
				     'POP billing fields are unavailable on this payment because the Paid Member Subscriptions module "Tax & EU VAT" is not active. Enable that module to edit the fiscal billing fields from this screen.',
				     WC_EL_INV_TEXTDOMAIN
			     ) .
			     '</p></div>';
			$this->renderCachedDocumentFilesPanel( $payment_id );
			return;
		}

		$customerType = null;
		foreach ( $this->admin_payment_billing_fields( $payment_id ) as $index => $field ) {
			$meta_value = \pms_get_payment_meta( $payment_id, $field['name'], true );
			if ( 'pms_invoice_type' === $field['name'] ) {
				$customerType = $meta_value;
			}

			if ( 'pms_choice_type' === $field['name'] && '' === $meta_value ) {
				$field['value'] = '';
			} elseif ( 'private' === $customerType && 'pms_vat_number' === $field['name'] ) {
				$field['value'] = '';
			} else {
				$field['value'] = ! empty( $meta_value ) ? $meta_value : $field['default'];
			}

			$this->printField( $field, $payment_id );
		}

		$this->renderCachedDocumentFilesPanel( $payment_id );

	}

	/**
	 * PMS exposes this helper only when the related tax/VAT module is loaded.
	 * Fall back to the addon tax settings to avoid fatals on admin payment pages.
	 *
	 * @return bool
	 */
	private function isPmsTaxEuVatEnabled() {

		if ( function_exists( 'pms_in_tax_eu_vat_enabled' ) ) {
			return (bool) pms_in_tax_eu_vat_enabled();
		}

		return (bool) TaxesProvider::get_tax_settings( 'enable_tax', false );
	}

	/**
	 * Get the billing fields for the admin payment form
	 *
	 * @param $payment_id
	 *
	 * @return array
	 */
	private function admin_payment_billing_fields( $payment_id = 0 ) {

		$payment = pms_get_payment( $payment_id );

		$customer_id = $payment && isset( $payment->user_id ) && $payment->user_id > 0 ? $payment->user_id : 0;

		// retrieve fields from POP and adding some payment fields like billing city, zip, etc
		$wcFields = [
			'pms_billing_first_name' => [
				'label'   => esc_attr__( 'First Name', WC_EL_INV_TEXTDOMAIN ),
				'id'      => 'pms_billing_first_name',
				'type'    => 'text',
				'default' => (string) get_user_meta( $customer_id, 'pms_billing_first_name', true ),
			],
			'pms_billing_last_name'  => [
				'label'   => esc_attr__( 'Last Name', WC_EL_INV_TEXTDOMAIN ),
				'type'    => 'text',
				'id'      => 'pms_billing_last_name',
				'default' => (string) get_user_meta( $customer_id, 'pms_billing_last_name', true ),
			],
			'pms_billing_email'      => [
				'label'   => esc_attr__( 'Email', WC_EL_INV_TEXTDOMAIN ),
				'type'    => 'email',
				'id'      => 'pms_billing_email',
				'default' => (string) get_user_meta( $customer_id, 'pms_billing_email', true ),
			],
			'pms_billing_company'    => [
				'label'   => esc_attr__( 'Billing Company', WC_EL_INV_TEXTDOMAIN ),
				'type'    => 'text',
				'id'      => 'pms_billing_company',
				'default' => (string) get_user_meta( $customer_id, 'pms_billing_company', true ),
			],
			'pms_billing_address'    => [
				'label'   => esc_attr__( 'Billing Address', WC_EL_INV_TEXTDOMAIN ),
				'type'    => 'text',
				'id'      => 'pms_billing_address',
				'default' => (string) pms_get_payment_meta( $payment_id, 'pms_billing_address', true ),
			],
			'pms_billing_city'       => [
				'label'   => esc_attr__( 'Billing City', WC_EL_INV_TEXTDOMAIN ),
				'type'    => 'text',
				'id'      => 'pms_billing_city',
				'default' => (string) pms_get_payment_meta( $payment_id, 'pms_billing_city', true ),
			],
			'pms_billing_zip'        => [
				'label'   => esc_attr__( 'Billing ZIP Code', WC_EL_INV_TEXTDOMAIN ),
				'type'    => 'text',
				'id'      => 'pms_billing_zip',
				'default' => (string) pms_get_payment_meta( $payment_id, 'pms_billing_zip', true ),
			],
			'pms_billing_state'      => [
				'label'   => esc_attr__( 'Billing State', WC_EL_INV_TEXTDOMAIN ),
				'type'    => 'text',
				'id'      => 'pms_billing_state',
				'default' => (string) pms_get_payment_meta( $payment_id, 'pms_billing_state', true ),
			],
			'pms_billing_country'    => [
				'label'   => esc_attr__( 'Billing Country', WC_EL_INV_TEXTDOMAIN ),
				'type'    => 'select',
				'id'      => 'pms_billing_country',
				'options' => \pms_get_countries(),
				'default' => '',
			]
		];

		if ( is_admin() ) {
			/** @var $wcFields array * */
			$wcFields = apply_filters( 'wc_el_inv-billing_fields', $wcFields );
		} else {
  		$wcFields = include_once \WcElectronInvoice\Plugin::getPluginDirPath( '/addon/for/cozmos/inc/billingFields.php' );
		}

		return $this->mapWcFieldsToPMSFields( $wcFields );

	}

	/**
	 * Map the WC billing fields to PMS fields
	 * for the PMS registration form
	 *
	 * @param $wcFields
	 *
	 * @return array
	 */
	private function mapWcFieldsToPMSFields( $wcFields ) {

		$tax_fields = array();
		$isPeppolContext = \WcElectronInvoice\Integrations::isPeppolContext();

		foreach ( $wcFields as $index => $field ) {

			// replace billing with pms only if is in the start of the string
			$index    = preg_replace( '/^billing/', 'pms', $index );
			$class    = preg_replace( '/_/', '-', $index );
			$required = isset( $field['required'] ) ? $field['required'] : 0;
			$default  = isset( $field['default'] ) ? $field['default'] : '';
			$type     = isset( $field['type'] ) ? $field['type'] : 'text';

			if ( 'hidden' === $type ) {
				continue;
			}

                if ( $isPeppolContext && in_array( $index, [ 'pms_sdi_type', 'pms_tax_code' ], true ) ) {
                    continue;
                }

			$tax_fields[ $index ] = array(
				'section'         => 'billing_details',
				'name'            => $index,
				'type'            => $type,
				'label'           => isset( $field['label'] ) ? $field['label'] : '',
				'description'     => isset( $field['description'] ) ? $field['description'] : '',
				'required'        => $required,
				'default'         => $default,
				'element_wrapper' => 'li',
				'wrapper_class'   => 'pms-' . $class,
			);

			// if select, add options
			if ( isset( $field['options'] ) ) {
				$tax_fields[ $index ]['options'] = $field['options'];
			}

		}

		return $tax_fields;
	}

	/**
	 * Render a read-only summary of cached generated files.
	 *
	 * @param int $payment_id
	 *
	 * @return void
	 */
	private function renderCachedDocumentFilesPanel( $payment_id = 0 ) {

		if ( $payment_id < 1 ) {
			return;
		}

		$order = $this->getOrder( $payment_id );
		if ( ! $order instanceof Order ) {
			return;
		}

		$entries = \WcElectronInvoice\Functions\getCachedDocumentAttachmentDisplayEntries( $order, true );
		?>
		<div class="cozmoslabs-form-subsection-wrapper" id="cozmoslabs-subsection-pop-generated-files">
			<h3 class="cozmoslabs-subsection-title"><?php esc_html_e( 'POP Generated Files Cache', WC_EL_INV_TEXTDOMAIN ); ?></h3>
			<p><?php esc_html_e( 'These cached files are cleared automatically when payment data changes and are rebuilt on the next document generation.', WC_EL_INV_TEXTDOMAIN ); ?></p>
			<?php if ( empty( $entries ) ) : ?>
				<div class="notice notice-info inline pms-notice"><p><?php esc_html_e( 'No cached generated files are currently stored for this payment.', WC_EL_INV_TEXTDOMAIN ); ?></p></div>
			<?php else : ?>
				<table class="widefat striped">
					<thead>
					<tr>
						<th><?php esc_html_e( 'Document', WC_EL_INV_TEXTDOMAIN ); ?></th>
						<th><?php esc_html_e( 'Format', WC_EL_INV_TEXTDOMAIN ); ?></th>
						<th><?php esc_html_e( 'Relative Path', WC_EL_INV_TEXTDOMAIN ); ?></th>
						<th><?php esc_html_e( 'Status', WC_EL_INV_TEXTDOMAIN ); ?></th>
					</tr>
					</thead>
					<tbody>
					<?php foreach ( $entries as $entry ) : ?>
						<tr>
							<td><?php echo esc_html( $entry['document_label'] ); ?></td>
							<td><?php echo esc_html( $entry['format_label'] ); ?></td>
							<td><code><?php echo esc_html( $entry['relative_path'] ); ?></code></td>
							<td><?php echo esc_html( $entry['exists'] ? __( 'Available on disk', WC_EL_INV_TEXTDOMAIN ) : __( 'Meta present but file missing', WC_EL_INV_TEXTDOMAIN ) ); ?></td>
						</tr>
					<?php endforeach; ?>
					</tbody>
				</table>
			<?php endif; ?>
		</div>
		<?php
	}

	/**
	 * @param $field
	 * @param $payment_id
	 *
	 * @return void
	 */
	private function printField( $field, $payment_id = 0 ) {

		// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
		ob_start(); ?>

      <div class="pms-form-field-<?php echo esc_attr( $field['wrapper_class'] ); ?> cozmoslabs-form-field-wrapper">
        <label class="cozmoslabs-form-field-label"
               for="pms-vat-number"><?php echo esc_attr( $field['label'] ); ?></label>
		  <?php switch ( esc_attr( $field['type'] ) ) {
			  case 'text': ?>
                <input type="text" name="<?php echo esc_attr( $field['name'] ); ?>"
                       id="<?php echo esc_attr( $field['name'] ); ?>"
                       class="cozmoslabs-form-field cozmoslabs-form-field-text"
                       value="<?php echo esc_attr( $field['value'] ); ?>"/>
				  <?php break;
			  case 'email': ?>
                <input type="text" name="<?php echo esc_attr( $field['name'] ); ?>"
                       id="<?php echo esc_attr( $field['name'] ); ?>"
                       class="cozmoslabs-form-field cozmoslabs-form-field-text"
                       value="<?php echo esc_attr( $field['value'] ); ?>"/>
				  <?php break;
			  case 'select': ?>
                <select name="<?php echo esc_attr( $field['name'] ); ?>" id="<?php echo esc_attr( $field['name'] ); ?>"
                        class="cozmoslabs-form-field cozmoslabs-form-field-select">
					<?php foreach ( $field['options'] as $key => $label ): ?>
                      <option <?php selected( $key, esc_attr( $field['value'] ) ) ?>
                          value="<?php echo esc_attr( $key ); ?>"><?php echo esc_html( $label ); ?></option>
					<?php endforeach; ?>
                </select>
				  <?php break;
		  } ?>
      </div>

		<?php
		// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
		echo ob_get_clean();
	}
}
