<?php
/**
 * User Handler
 *
 * @category   WordPress_Plugin
 * @package    Common
 * @subpackage Handlers\Rest_API
 * @author     miniOrange <info@miniorange.com>
 * @license    MIT/Expat
 * @link       https://plugins.miniorange.com/woocommerce-api-product-sync-with-woocommerce-rest-apis
 */

namespace MOWCPS\Common\Handlers\Rest_API;

use WP_Error;
use MOWCPS\Common\Constants\Constants;
use MOWCPS\Common\Utils\Model_Utils;
use MOWCPS\Common\Utils\Utils;
use MOWCPS\Common\Constants\User_Constants;
use MOWCPS\Common\Services\API\API_Service;

if ( ! defined( 'ABSPATH' ) ) {
	die;
}

/**
 * Class User_Handler.
 *
 * Handles user REST API operations
 */
class User_Handler {

	/**
	 * API service instance
	 *
	 * @var API_Service
	 */
	protected $api_service;

	/**
	 * Utils instance
	 *
	 * @var Utils
	 */
	private $utils;

	/**
	 * Constructor
	 */
	public function __construct() {
		$this->api_service = new API_Service();

		$namespace   = false !== strpos( Constants::MOWCPS_PLAN_NAME, 'standard' ) ? 'Standard' : MOWCPS_PLAN_NAMESPACE;
		$this->utils = 'MOWCPS\\' . $namespace . '\Utils\Utils';
	}

	/**
	 * Login user
	 *
	 * @param string $email Email.
	 * @param string $password Password.
	 * @return string|WP_Error
	 */
	public function login( $email, $password ) {
		$verify_customer_response = $this->get_customer_key( $email, $password );
		$verify_customer_response = json_decode( $verify_customer_response['body'], true );

		if ( is_array( $verify_customer_response ) && isset( $verify_customer_response['status'] ) && 'SUCCESS' === $verify_customer_response['status'] ) {

			$option_name  = base64_encode( 'mowcps_user_details' ); // phpcs:ignore --WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode Not used for code obfuscation.
			Model_Utils::delete_option( $option_name );
			$key_name     = base64_encode( 'mowcps_customer_token' ); // phpcs:ignore
			$user_details = array();

			$user_details[ $key_name ] = base64_encode( $verify_customer_response['token'] ); //phpcs:ignore
			Model_Utils::update_option( $option_name, $user_details );

			// Storing required customer details in DB.
			$customer_details = array(
				'mowcps_customer_email'     => $email,
				'mowcps_customer_logged_in' => 'Logged in',
				'mowcps_customer_id'        => $verify_customer_response['id'],
				'mowcps_customer_api_key'   => $verify_customer_response['apiKey'],
			);

			foreach ( $customer_details as $key => $value ) {
				$encoded_key   = $this->utils::encoder( $key );
				$encoded_value = $this->utils::encoder( $value );
				if ( false !== $encoded_key && false !== $encoded_value ) {
					$user_details[ $encoded_key ] = $encoded_value;
				}
			}

			Model_Utils::update_option( $option_name, $user_details );

			// For user display details.
			Model_Utils::update_option(
				'mowcps_user_display_details',
				array(
					'user_email' => $email,
					'user_id'    => $verify_customer_response['id'],
				)
			);
			return 'Successfully logged in';
		} else {
			return new WP_Error(
				'FAILED',
				$verify_customer_response['message'] ?? 'Failed to login!',
				array( 'status' => Constants::HTTP_BAD_REQUEST )
			);
		}
	}

	/**
	 * Get customer key
	 *
	 * @param string $email Email.
	 * @param string $password Password.
	 * @return array|WP_Error
	 */
	private function get_customer_key( $email, $password ) {
		$request_parameters = Utils::generate_request_parameters();

		$api_request = array(
			'endpoint' => Constants::MOWCPS_HOST_NAME . '/moas/rest/customer/key',
			'method'   => Constants::HTTP_REQUEST_METHOD_POST,
			'headers'  => $request_parameters['headers'],
			'body'     => wp_json_encode(
				array(
					'email'    => $email,
					'password' => $password,
				)
			),
		);

		$api_request = array_merge( $api_request, $request_parameters['args'] );

		$response = $this->api_service::make_api_call( $api_request['endpoint'], $api_request );

		if ( is_wp_error( $response ) ) {
			return $response;
		}

		return $response;
	}

	/**
	 * Contact us
	 *
	 * @param string $email Email.
	 * @param string $phone Phone.
	 * @param string $query Query.
	 * @param string $request_type Request type.
	 * @param string $subject Subject.
	 * @param string $content Content.
	 * @return array|WP_Error
	 */
	public function contact_us( $email, $phone, $query, $request_type = '', $subject = null, $content = null ) {
		if ( null === $subject ) {
			$subject = 'Query: Product Sync for WooCommerce - ' . MOWCPS_VERSION . ' Plugin';
		}

		$current_user = wp_get_current_user();

		$option_name  = base64_encode( 'mowcps_user_details' ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode -- Not used for code obfuscation.
		$user_details = Model_Utils::get_option( $option_name, array() );

		$customer_id      = '';
		$customer_api_key = '';

		if ( $user_details ) {
			$customer_id      = $this->utils::encoder( 'mowcps_customer_id' );
			$customer_api_key = $this->utils::encoder( 'mowcps_customer_api_key' );
		}

		$customer_key = ! empty( $user_details[ $customer_id ] ) ? $this->utils::decoder( $user_details[ $customer_id ] ) : User_Constants::DEFAULT_CUSTOMER_KEY;
		$api_key      = ! empty( $user_details[ $customer_api_key ] ) ? $this->utils::decoder( $user_details[ $customer_api_key ] ) : User_Constants::DEFAULT_API_KEY;

		$query   = '[Product Sync for WooCommerce : ' . MOWCPS_VERSION . '] ' . $query;
		$server  = isset( $_SERVER['SERVER_NAME'] ) ? sanitize_text_field( wp_unslash( $_SERVER['SERVER_NAME'] ) ) : '';
		$content = $content ?? '<div >Hello, <br><br>First Name :' . $current_user->user_firstname . '<br><br>Last  Name :' . $current_user->user_lastname . '   <br><br>Company :<a href="' . $server . '" target="_blank" >' . $server . '</a><br><br>Phone Number :' . $phone . '<br><br>Email :<a href="mailto:' . $email . '" target="_blank">' . $email . '</a><br><br>Query :' . $query . '</div>';

		if ( ! empty( $request_type ) ) {
			$content .= '<br><br><b>Request Type :</b>' . $request_type;
		}

		$credentials = array(
			'customer_key' => $customer_key,
			'api_key'      => $api_key,
		);

		$timestamp = round( microtime( true ) * 1000 );
		$timestamp = number_format( $timestamp, 0, '', '' );

		$api_request = array(
			'endpoint'    => Constants::MOWCPS_HOST_NAME . '/moas/api/notify/send',
			'method'      => Constants::HTTP_REQUEST_METHOD_POST,
			'headers'     => $this->generate_auth_data( $credentials, $timestamp )['headers'],
			'body'        => wp_json_encode(
				array(
					'customerKey' => $customer_key,
					'sendEmail'   => true,
					'email'       => array(
						'customerKey' => $customer_key,
						'fromEmail'   => $email,
						'bccEmail'    => Constants::SUPPORT_BCC_EMAIL,
						'fromName'    => Constants::EMAIL_FROM_NAME,
						'toEmail'     => Constants::SUPPORT_EMAIL,
						'toName'      => Constants::SUPPORT_EMAIL,
						'subject'     => $subject,
						'content'     => $content,
					),
				)
			),
			'timeout'     => '20',
			'redirection' => '5',
			'httpversion' => '1.0',
			'blocking'    => true,
			'sslverify'   => true,
		);

		$response = $this->api_service::make_api_call( $api_request['endpoint'], $api_request );

		if ( is_wp_error( $response ) ) {
			return $response;
		}

		$response = json_decode( $response['body'], true );

		return $response;
	}

	/**
	 * Handle user trial request
	 *
	 * @param string $email Email.
	 * @param array  $supplier Suppliers.
	 * @param string $documentation Documentation.
	 * @param string $use_case Use case.
	 * @return array|WP_Error
	 */
	public function trial_request( $email, $supplier, $documentation, $use_case ) {
		$subject = 'Trial Request: Product Sync for WooCommerce Plugin';

		$query = 'Hello team,<br><br>The user has requested the trial for the Product Sync for WooCommerce plugin with the following details: <br><br><b>Email: </b>' . $email . '<br><b>Use Case: </b>' . $use_case . '<br><b>Documentation: </b>' . $documentation . '<br><b>External Suppliers: </b>' . implode( ', ', $supplier ) . '<br><br><b>Version: </b>' . MOWCPS_VERSION;

		$result = $this->contact_us( $email, '', $query, '', $subject, $query );

		return $result;
	}

	/**
	 * Generate authentication data
	 *
	 * @param array  $credentials Customer credentials.
	 * @param string $timestamp   Current timestamp.
	 * @return array Authentication headers and data.
	 */
	protected function generate_auth_data( $credentials, $timestamp ) {
		$string_to_hash = $credentials['customer_key'] . $timestamp . $credentials['api_key'];
		$hash_value     = hash( 'sha512', $string_to_hash );

		return array(
			'headers' => array(
				'Content-Type'  => 'application/json',
				'Customer-Key'  => $credentials['customer_key'],
				'Timestamp'     => $timestamp,
				'Authorization' => $hash_value,
			),
			'body'    => wp_json_encode(
				array(
					'customerId'      => $credentials['customer_key'],
					'applicationName' => str_replace( '_plan', '', Constants::MOWCPS_PLAN_NAME ),
				)
			),
		);
	}

	/**
	 * Get user details
	 *
	 * @return array|WP_Error User details or WP_Error if not found.
	 */
	public function get_user_details() {
		if ( ! $this->is_customer_session_valid() ) {
			return new WP_Error(
				Constants::ERROR_RECORD_NOT_FOUND,
				Constants::MSG_RECORD_NOT_FOUND,
				array()
			);
		}

		$user_display_details = Model_Utils::get_option( 'mowcps_user_display_details', array() );

		if ( empty( $user_display_details ) ) {
			return new WP_Error(
				Constants::ERROR_RECORD_NOT_FOUND,
				Constants::MSG_RECORD_NOT_FOUND,
				$user_display_details
			);
		}

		return $user_display_details;
	}

	/**
	 * True when the stored miniOrange session (token + customer id + logged-in flag) exists.
	 *
	 * @return bool
	 */
	private function is_customer_session_valid() {
		$option_name  = base64_encode( 'mowcps_user_details' ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode -- Not used for code obfuscation.
		$user_details = Model_Utils::get_option( $option_name, array() );

		if ( empty( $user_details ) || ! is_array( $user_details ) ) {
			return false;
		}

		$token_key = base64_encode( 'mowcps_customer_token' ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode -- Not used for code obfuscation.
		if ( empty( $user_details[ $token_key ] ) ) {
			return false;
		}

		$logged_in_key = $this->utils::encoder( 'mowcps_customer_logged_in' );
		if ( false === $logged_in_key ) {
			return false;
		}

		$logged_in = isset( $user_details[ $logged_in_key ] ) ? $this->utils::decoder( $user_details[ $logged_in_key ] ) : '';
		if ( 'Logged in' !== $logged_in ) {
			return false;
		}

		$customer_id_key = $this->utils::encoder( 'mowcps_customer_id' );
		if ( false === $customer_id_key ) {
			return false;
		}

		$customer_id = isset( $user_details[ $customer_id_key ] ) ? $this->utils::decoder( $user_details[ $customer_id_key ] ) : '';
		if ( '' === $customer_id || ! is_numeric( trim( $customer_id ) ) ) {
			return false;
		}

		return true;
	}
}
