<?php

namespace  EverestForms\Pro\Addons\Square\Api;

use Square\Environment;
use Square\Models\Card;
use Square\Models\Order;
use Square\Models\Money;
use Square\Models\Address;
use Square\Models\Customer;
use Square\Models\OrderSource;
use Square\Models\CatalogItem;
use Square\SquareClientBuilder;
use Square\Models\CatalogObject;
use Square\Models\PhaseRotation;
use Square\Exceptions\ApiException;
use Square\Models\SubscriptionPhase;
use Square\Models\CreateOrderRequest;
use Square\Models\CreatePaymentRequest;
use Square\Models\CatalogItemVariation;
use Square\Models\CreateCustomerRequest;
use Square\Models\CatalogSubscriptionPlan;
use Square\Models\CreateCustomerCardRequest;
use Square\Models\CreateSubscriptionRequest;
use Square\Models\UpsertCatalogObjectRequest;
use Square\Authentication\BearerAuthCredentialsBuilder;

class Api {

	/**
	 * Access token.
	 *
	 * @since 1.0.0
	 * @var string
	 */
	private static $access_token;


	/**
	 * Item.
	 *
	 * @since 1.0.0
	 *
	 * @var string
	 */
	private static $item_data;

	/**
	 * Customer.
	 *
	 * @since 1.0.0
	 *
	 * @var string
	 */
	private static $customer;

	/**
	 * Variation.
	 *
	 * @since 1.0.0
	 *
	 * @var string
	 */
	private static $variation;

	/**
	 * Card.
	 *
	 * @since 1.0.0
	 *
	 * @var string
	 */
	private static $card;

	/**
	 * Plan.
	 *
	 * @since 1.0.0
	 *
	 * @var string
	 */
	private static $plan;

	/**
	 * Subscription.
	 *
	 * @since 1.0.0
	 *
	 * @var string
	 */
	private static $subscription;

	/**
	 * Idempotancy Key.
	 *
	 * @since 1.0.0
	 */
	private static $idempotency_key;

	/**
	 * Location id.
	 *
	 * @since 1.0.0
	 */
	private static $location_id;
	/**
	 * Create client instance.
	 *
	 * @since 1.0.0
	 *
	 * @return mixed CLient instance.
	 */
	public static function get_client() {
		$mode               = 'yes' === get_option( 'everest_forms_pro_square_test_mode' ) ? 'test' : 'live';
		self::$access_token = get_option( 'everest_forms_square_' . $mode . '_access_token' );

		$client = 'yes' === get_option( 'everest_forms_pro_square_test_mode' ) ? SquareClientBuilder::init()
		->bearerAuthCredentials(
			BearerAuthCredentialsBuilder::init(
				self::$access_token
			)
		)
				->environment( Environment::SANDBOX )
				->build() : SquareClientBuilder::init()
				->bearerAuthCredentials(
					BearerAuthCredentialsBuilder::init(
						self::$access_token
					)
				)
						->environment( Environment::PRODUCTION )
						->build();
			return $client;
	}

	/**
	 * Create payment.
	 *
	 * @since 1.0.0
	 *
	 * @param  array $payment_details Payment Details.
	 */
	public static function create_payment( $payment_details ) {
		$client = self::get_client();

		$source_id             = $payment_details['source_id'];
		self::$idempotency_key = $payment_details['idempotency_key'];
		self::$location_id     = $payment_details['location_id'];
		$total_amount          = empty( $payment_details['payment_data']['total'] ) ? 0 : $payment_details['payment_data']['total'];
		$form_id               = empty( $payment_details['payment_data']['form_id'] ) ? '' : $payment_details['payment_data']['form_id'];
		$form                  = EVF()->form->get( $form_id );
		$form_data             = ! empty( $form->post_content ) ? evf_decode( $form->post_content ) : '';
		$payments              = isset( $form_data['payments'] ) ? $form_data['payments'] : array();
		$currency              = get_option( 'everest_forms_currency' );

		if ( '1' != $payments['square']['enable_square'] ) {
			wp_send_json_error(
				array(
					'detail' => 'Square payment is not enabled.'
				)
			);
		}

		$customer_details = self::create_customer( $payment_details, $payments );

		if ( is_array( $customer_details ) && isset( $customer_details['customer_id'] ) ) {
			$customer_id = $customer_details['customer_id'];
		} elseif ( is_array( $customer_details ) && ! empty( $customer_details[0]->getDetail() ) ) {
			wp_send_json_error( $customer_details );
		} else {
			$customer_id = $customer_details->getCustomer()->getId();
		}

		if ( 0 === $total_amount ) {
			return wp_send_json_error(
				array( 'message' => 'Total is zero' )
			);
		}

		$amount_money = new Money();
		$amount_money->setAmount( $total_amount * 100 );
		$amount_money->setCurrency( $currency );

		$body = new CreatePaymentRequest( $source_id, self::$idempotency_key );

		$body->setCustomerId( $customer_id );
		$body->setAmountMoney( $amount_money );
		$body->setLocationId( self::$location_id );

		$payment_response = $client->getPaymentsApi()->createPayment( $body );

		if ( $payment_response->isSuccess() ) {
			$result = $payment_response->getResult();
			wp_send_json_success( $result );
		} else {
			$errors = $payment_response->getErrors();
			wp_send_json_error( $errors );
		}

	}


	/**
	 * Create customer.
	 *
	 * @since 1.7.5
	 *
	 * @param  array  $payment_details Payment details from user.
	 * @param  array  $payments List of payments in everest forms.
	 * @param  string $email Email.
	 */
	protected static function create_customer( $payment_details, $payments ) {
		$client = self::get_client();

		$payment_data    = $payment_details['payment_data']['data'];
		$customer_fields = array(
			'first_name'      => empty( $payments['square']['customer_first_name'] ) ? '' : $payments['square']['customer_first_name'],
			'last_name'       => empty( $payments['square']['customer_last_name'] ) ? '' : $payments['square']['customer_last_name'],
			'billing_address' => empty( $payments['square']['customer_billing_address'] ) ? '' : $payments['square']['customer_billing_address'],
			'email'           => empty( $payments['square']['customer_email'] ) ? '' : $payments['square']['customer_email']
		);

		$customer_info = array(
			'first_name'      => '',
			'last_name'       => '',
			'billing_address' => new Address(),
			'email'           => ''
		);

		foreach ( $payment_data as $data ) {
			foreach ( $customer_fields as $field => $field_id ) {
				if ( $field_id && strpos( $data['name'], $field_id ) !== false ) {
					switch ( $field ) {
						case 'first_name':
						case 'last_name':
						case 'email':
							$customer_info[ $field ] = $data['value'];
							break;
						case 'billing_address':
							self::set_address_field( $customer_info['billing_address'], $data['name'], $data['value'] );
							break;
					}
				}
			}
		}

		$customers_lists = self::list_of_customers();

		if ( ! empty( $customers_lists->getErrors() ) ) {
			wp_send_json_error( $customers_lists->getErrors() );
		}

		foreach ( $customers_lists->getCustomers() as $customer ) {
			if ( $customer->getEmailAddress() === $customer_info['email'] ) {
				return array( 'customer_id' => $customer->getId() );
			}
		}

		$body = new CreateCustomerRequest();
		$body->setGivenName( $customer_info['first_name'] );
		$body->setFamilyName( $customer_info['last_name'] );
		$body->setEmailAddress( $customer_info['email'] );
		$body->setAddress( $customer_info['billing_address'] );

		$create_customer_response = $client->getCustomersApi()->createCustomer( $body );

		if ( $create_customer_response->isSuccess() ) {
			return $create_customer_response->getResult();
		} else {
			return $create_customer_response->getErrors();
		}
	}

	/**
	 * Set address fields.
	 *
	 * @param Address $address Address Object.
	 * @param string  $name Name of field.
	 * @param string  $value Value of field.
	 */
	protected static function set_address_field( Address $address, $name, $value ) {
		if ( strpos( $name, 'address1' ) !== false ) {
			$address->setAddressLine1( $value );
		} elseif ( strpos( $name, 'address2' ) !== false ) {
			$address->setAddressLine2( $value );
		} elseif ( strpos( $name, 'city' ) !== false ) {
			$address->setLocality( $value );
		} elseif ( strpos( $name, 'postal' ) !== false ) {
			$address->setPostalCode( $value );
		} elseif ( strpos( $name, 'country' ) !== false ) {
			$address->setCountry( $value );
		}
	}

	/**
	 * List of customers.
	 *
	 * @since 1.7.5
	 */
	protected static function list_of_customers() {
		$client       = self::get_client();
		$api_response = $client->getCustomersApi()->listCustomers();

		if ( $api_response->isSuccess() ) {
			return $api_response->getResult();
		} else {
			return $api_response->getErrors();
		}
	}
}
