<?php
/**
 * User Service
 *
 * Handles miniOrange (xecurify) login and registration API calls
 * and persists minimal user state in WordPress options using
 * secure XOR + Base64 encoding.
 *
 * @package    MOMCS_Sync
 * @subpackage MOMCS_Sync\includes\common\services
 */

declare(strict_types=1);

namespace MOMCS_Sync\Includes\Common\Services;

use MOMCS_Sync\Includes\Common\Constants\Plugin_Constants;
use MOMCS_Sync\Includes\Common\Utils\User_Storage_Utils;

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

/**
 * Class User_Service
 *
 * Manages user authentication and credential storage with secure encoding.
 */
class User_Service {

	/**
	 * Legacy option key for backward compatibility.
	 */
	private const OPTION_KEY = 'momcs_miniorange_user';

	/**
	 * Base64-encoded option name for secure user details storage.
	 * Decodes to: momcs_user_details
	 * Must match the option name used by license library (Mo_License_Service_Utility).
	 */
	private const ENCODED_OPTION_KEY = 'bW9tY3NfdXNlcl9kZXRhaWxz';

	/**
	 * Display details option for UI (non-sensitive).
	 * Must match Mo_License_Config::CUSTOMER_EMAIL_OPTION for license library compatibility.
	 */
	private const DISPLAY_OPTION_KEY = 'momcs_user_display_details';

	/**
	 * All license-related options to clean on account change/deactivation.
	 */
	private const LICENSE_OPTIONS = array(
		'momcs_miniorange_user',       // Legacy plain text option.
		'bW9tY3NfdXNlcl9kZXRhaWxz',    // Encoded user details (base64 of 'momcs_user_details').
		'bW93Y3BzX3VzZXJfZGV0YWlscw==', // Legacy encoded option (base64 of 'mowcps_user_details').
		'momcs_user_display_details',  // Display details for UI (matches Mo_License_Config).
		'momcs_lk',                    // License key.
		'momcs_led',                   // Encrypted license expiry date.
		'momcs_tla',                   // Trial license status.
		'momcs_license_expired',       // License expired flag.
		'momcs_ln_check_t',            // Last license check timestamp.
		'momcs_exp_notice_close',      // Expiry notice dismissed flag.
	);

	/**
	 * Verify login and persist user data with secure encoding.
	 *
	 * Flow:
	 * 1. Call miniOrange API to verify credentials
	 * 2. Store token in base64 (used as encoding key)
	 * 3. XOR encode all other customer details with the token
	 * 4. Store encoded data in database
	 *
	 * @param string $email    Email address.
	 * @param string $password Password.
	 * @return array|\WP_Error Array with stored fields on success; error on failure.
	 */
	public function verify_and_store_customer( string $email, string $password ) {
		$body     = wp_json_encode(
			array(
				'email'    => $email,
				'password' => $password,
			)
		);
		$response = wp_remote_post(
			Plugin_Constants::CUSTOMER_KEY_API,
			array(
				'headers'   => array( 'Content-Type' => 'application/json; charset=utf-8' ),
				'body'      => $body,
				'timeout'   => 20,
				'sslverify' => true,
			)
		);

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

		$code = (int) wp_remote_retrieve_response_code( $response );
		$raw  = wp_remote_retrieve_body( $response );
		$data = json_decode( $raw, true );

		if ( 200 !== $code || ! is_array( $data ) || ( $data['status'] ?? '' ) !== 'SUCCESS' ) {
			return new \WP_Error(
				'momcs_login_failed',
				__( 'Login failed. Please check your credentials and try again.', 'multi-channel-for-woocommerce' ),
				array(
					'response' => $raw,
					'code'     => $code,
				)
			);
		}

		// Extract and validate response data.
		$customer_email  = (string) ( $data['email'] ?? $email );
		$customer_id     = (string) ( $data['id'] ?? '' );
		$customer_token  = (string) ( $data['token'] ?? '' );
		$customer_apikey = (string) ( $data['apiKey'] ?? '' );

		if ( empty( $customer_token ) ) {
			return new \WP_Error(
				'momcs_login_failed',
				__( 'Login failed. Invalid response from server.', 'multi-channel-for-woocommerce' ),
				array( 'response' => $raw )
			);
		}

		// Store encoded user details for license library compatibility.
		$this->store_encoded_user_details( $customer_email, $customer_id, $customer_token, $customer_apikey );

		// Store display details for UI (non-sensitive).
		update_option(
			self::DISPLAY_OPTION_KEY,
			array(
				'user_email' => $customer_email,
				'user_id'    => $customer_id,
			),
			false
		);

		// Return normalized data for handler.
		$stored = array(
			'email'       => $customer_email,
			'customer_id' => $customer_id,
			'api_key'     => $customer_apikey,
			'token'       => $customer_token,
			'logged_in'   => true,
		);

		// Legacy storage for backward compatibility.
		update_option( self::OPTION_KEY, $stored, false );

		return $stored;
	}

	/**
	 * Store user details with XOR + Base64 encoding.
	 *
	 * Storage structure:
	 * - base64('momcs_customer_token') => base64(token)
	 * - XOR_encoded('momcs_customer_email') => XOR_encoded(email)
	 * - XOR_encoded('momcs_customer_id') => XOR_encoded(customer_id)
	 * - XOR_encoded('momcs_customer_api_key') => XOR_encoded(api_key)
	 * - XOR_encoded('momcs_customer_logged_in') => XOR_encoded('Logged in')
	 *
	 * @param string $email      Customer email.
	 * @param string $id         Customer ID.
	 * @param string $token      Customer token (used as encoding key).
	 * @param string $api_key    Customer API key.
	 * @return bool True on success.
	 */
	private function store_encoded_user_details( string $email, string $id, string $token, string $api_key ): bool {
		// First, clear any existing data.
		delete_option( self::ENCODED_OPTION_KEY );

		// Store token first (base64 encoded, used as encryption key).
		// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode -- Required for secure storage.
		$token_key   = base64_encode( User_Storage_Utils::KEY_CUSTOMER_TOKEN );
		// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode -- Required for secure storage.
		$token_value = base64_encode( $token );

		$user_details = array(
			$token_key => $token_value,
		);

		// Save token first so encoder can use it.
		update_option( self::ENCODED_OPTION_KEY, $user_details, false );

		// Now encode and store other details using the token.
		$details_to_encode = array(
			User_Storage_Utils::KEY_CUSTOMER_EMAIL     => $email,
			User_Storage_Utils::KEY_CUSTOMER_ID        => $id,
			User_Storage_Utils::KEY_CUSTOMER_API_KEY   => $api_key,
			User_Storage_Utils::KEY_CUSTOMER_LOGGED_IN => 'Logged in',
		);

		foreach ( $details_to_encode as $key => $value ) {
			$encoded_key   = User_Storage_Utils::encoder( $key );
			$encoded_value = User_Storage_Utils::encoder( $value );

			if ( false !== $encoded_key && false !== $encoded_value ) {
				$user_details[ $encoded_key ] = $encoded_value;
			}
		}

		return update_option( self::ENCODED_OPTION_KEY, $user_details, false );
	}

	/**
	 * Register account and return normalized response.
	 *
	 * @param string $email    Email address.
	 * @param string $password Password.
	 * @return array|\WP_Error
	 */
	public function create_and_store_customer( string $email, string $password ) {
		$body     = wp_json_encode(
			array(
				'email'          => $email,
				'password'       => $password,
				'areaOfInterest' => 'Multi-channel for WooCommerce',
			)
		);
		$response = wp_remote_post(
			Plugin_Constants::CUSTOMER_ADD_API,
			array(
				'headers'   => array( 'Content-Type' => 'application/json; charset=utf-8' ),
				'body'      => $body,
				'timeout'   => 20,
				'sslverify' => true,
			)
		);
		if ( is_wp_error( $response ) ) {
			return $response;
		}

		$code = (int) wp_remote_retrieve_response_code( $response );
		$raw  = wp_remote_retrieve_body( $response );
		$data = json_decode( $raw, true );

		if ( 200 !== $code || ! is_array( $data ) ) {
			return new \WP_Error(
				'momcs_register_failed',
				__( 'Registration failed. Please try again.', 'multi-channel-for-woocommerce' ),
				array(
					'response' => $raw,
					'code'     => $code,
				)
			);
		}

		// Normalize messages similar to the doc.
		$status  = (string) ( $data['status'] ?? '' );
		$message = (string) ( $data['message'] ?? '' );
		if ( 'SUCCESS' === $status ) {
			return array(
				'status'  => 'SUCCESS',
				'message' => $message ?? 'Account created successfully.',
			);
		}

		// Known codes mapping.
		$friendly = $message;
		if ( 'TRANSACTION_LIMIT_EXCEEDED' === ( $data['code'] ?? '' ) ) {
			$friendly = __( 'Too many attempts. Please try again later.', 'multi-channel-for-woocommerce' );
		} elseif ( 'CUSTOMER_USERNAME_ALREADY_EXISTS' === ( $data['code'] ?? '' ) ) {
			$friendly = __( 'This email is already registered. Please sign in.', 'multi-channel-for-woocommerce' );
		} elseif ( ! $friendly ) {
			$friendly = __( 'Registration failed.', 'multi-channel-for-woocommerce' );
		}

		return array(
			'status'  => 'ERROR',
			'message' => $friendly,
		);
	}

	/**
	 * Get current stored user record.
	 *
	 * Attempts to retrieve from encoded storage first, then falls back
	 * to legacy storage for backward compatibility.
	 *
	 * @return array|null User data array or null if not found.
	 */
	public function get_user(): ?array {
		// Try to get from encoded storage first.
		$decoded_user = $this->get_decoded_user_details();
		if ( null !== $decoded_user ) {
			return $decoded_user;
		}

		// Fallback to legacy storage.
		$value = get_option( self::OPTION_KEY );
		return is_array( $value ) ? $value : null;
	}

	/**
	 * Decode and retrieve user details from secure storage.
	 *
	 * @return array|null Decoded user data or null if not available.
	 */
	private function get_decoded_user_details(): ?array {
		$user_details = get_option( self::ENCODED_OPTION_KEY, array() );

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

		// Check if token exists (required for decoding).
		// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode -- Required for key lookup.
		$token_key = base64_encode( User_Storage_Utils::KEY_CUSTOMER_TOKEN );
		if ( ! isset( $user_details[ $token_key ] ) ) {
			return null;
		}

		// Decode user details.
		$decoded = array(
			'logged_in' => false,
		);

		// Get email.
		$email_key = User_Storage_Utils::encoder( User_Storage_Utils::KEY_CUSTOMER_EMAIL );
		if ( false !== $email_key && isset( $user_details[ $email_key ] ) ) {
			$decoded['email'] = User_Storage_Utils::decoder( $user_details[ $email_key ] );
		}

		// Get customer ID.
		$id_key = User_Storage_Utils::encoder( User_Storage_Utils::KEY_CUSTOMER_ID );
		if ( false !== $id_key && isset( $user_details[ $id_key ] ) ) {
			$decoded['customer_id'] = User_Storage_Utils::decoder( $user_details[ $id_key ] );
		}

		// Get API key.
		$api_key = User_Storage_Utils::encoder( User_Storage_Utils::KEY_CUSTOMER_API_KEY );
		if ( false !== $api_key && isset( $user_details[ $api_key ] ) ) {
			$decoded['api_key'] = User_Storage_Utils::decoder( $user_details[ $api_key ] );
		}

		// Get token.
		// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode -- Required for token retrieval.
		$decoded['token'] = base64_decode( $user_details[ $token_key ], true );

		// Get logged in status.
		$logged_in_key = User_Storage_Utils::encoder( User_Storage_Utils::KEY_CUSTOMER_LOGGED_IN );
		if ( false !== $logged_in_key && isset( $user_details[ $logged_in_key ] ) ) {
			$logged_in_value      = User_Storage_Utils::decoder( $user_details[ $logged_in_key ] );
			$decoded['logged_in'] = ( 'Logged in' === $logged_in_value );
		}

		// Return only if we have valid data.
		if ( ! empty( $decoded['email'] ) && ! empty( $decoded['customer_id'] ) ) {
			return $decoded;
		}

		return null;
	}

	/**
	 * Clear all user login state and license data.
	 *
	 * This method is called when:
	 * - User clicks "Change Account"
	 * - Plugin is deactivated
	 *
	 * It clears ALL user and license related options to ensure
	 * a clean slate for the next login.
	 *
	 * @return void
	 */
	public function clear_user(): void {
		// Delete all license and user related options.
		foreach ( self::LICENSE_OPTIONS as $option ) {
			delete_option( $option );
		}
	}

	/**
	 * Get display-safe user details (for UI rendering).
	 *
	 * @return array|null Array with 'user_email' and 'user_id' or null.
	 */
	public function get_display_details(): ?array {
		$display = get_option( self::DISPLAY_OPTION_KEY );
		if ( is_array( $display ) && ! empty( $display['user_email'] ) ) {
			return $display;
		}

		// Fallback: construct from decoded user.
		$user = $this->get_user();
		if ( null !== $user ) {
			return array(
				'user_email' => $user['email'] ?? '',
				'user_id'    => $user['customer_id'] ?? '',
			);
		}

		return null;
	}

	/**
	 * Check if user is logged in to miniOrange account.
	 *
	 * @return bool True if logged in, false otherwise.
	 */
	public function is_logged_in(): bool {
		$user = $this->get_user();
		return is_array( $user ) && ( $user['logged_in'] ?? false );
	}
}
