<?php
/**
 * Account Profile Fields Registry
 *
 * Defines and renders profile fields for ambassador accounts.
 *
 * @package AmbassadorHub\Accounts
 */

namespace AmbassadorHub\Accounts;

use AmbassadorHub\Accounts\Admin\Settings\SettingsManager;
use AmbassadorHub\Fields\FieldFactory;

use WP_User;
use function apply_filters;
use function esc_html__;
use function get_user_by;
use function get_user_meta;
use function in_array;
use function is_array;
use function sanitize_text_field;
use function wp_unslash;
use function update_user_meta;
use function wp_update_user;

/**
 * Registry and helpers for account profile fields.
 */
final class AccountFields {
	/**
	 * Request field group name for profile fields.
	 */
	private const FIELD_GROUP = 'ambh_profile_fields';

	/**
	 * Get all registered account fields for a given context.
	 *
	 * @param string $context Rendering or saving context (signup|profile|payload).
	 *
	 * @return array<string,array> Field definitions keyed by field ID.
	 */
	public static function get_fields( string $context = 'profile' ): array {

		$fields = self::get_default_fields();

		/**
		 * Filter account profile field registry.
		 *
		 * @since 0.1.0
		 *
		 * @param array  $fields  Field definitions keyed by field ID.
		 * @param string $context Context (signup|profile|payload).
		 */
		$fields = apply_filters( 'ambh_account_profile_fields_registry', $fields, $context );
		return is_array( $fields ) ? $fields : array();
	}

	/**
	 * Render signup fields.
	 *
	 * @return void
	 */
	public static function render_signup_fields(): void {
		self::render_fields( null, 'signup' );
	}

	/**
	 * Render profile fields.
	 *
	 * @param WP_User $user Current user.
	 *
	 * @return void
	 */
	public static function render_profile_fields( WP_User $user ): void {
		self::render_fields( $user, 'profile' );
	}

	/**
	 * Save fields from a request payload.
	 *
	 * @param int    $user_id User ID.
	 * @param array  $source  Request source (usually $_POST).
	 * @param string $context Context (signup|profile).
	 *
	 * @return void
	 */
	public static function save_from_request( int $user_id, array $source, string $context ): void {

		if ( empty( $source[ self::FIELD_GROUP ] ) || ! is_array( $source[ self::FIELD_GROUP ] ) ) {
			return;
		}

		$input  = $source[ self::FIELD_GROUP ];
		$fields = self::get_fields( $context );

		foreach ( $fields as $field_id => $field ) {

			$meta_key = $field['meta_key'] ?? '';
			if ( ! $meta_key ) {
				continue;
			}

			// Other field types.
			if ( ! isset( $input[ $meta_key ] ) ) {
				continue;
			}

			$raw_value       = $input[ $meta_key ];
			$sanitized_value = self::sanitize_field_value(
				$raw_value,
				$field,
				'save'
			);

			update_user_meta( $user_id, $meta_key, $sanitized_value );
		}
	}

	/**
	 * Get payload fields for extensions.
	 *
	 * @param int $user_id User ID.
	 *
	 * @return array<string,mixed>
	 */
	public static function get_payload_fields( int $user_id ): array {

		$payload = array();
		$fields  = self::get_fields( 'payload' );

		foreach ( $fields as $field_id => $field ) {
			if ( false === ( $field['enable_in_payload'] ?? true ) ) {
				continue;
			}

			$meta_key = $field['meta_key'] ?? '';
			if ( ! $meta_key ) {
				continue;
			}

			// Sanitize value for payload based on field type.
			$sanitized_value      = self::sanitize_field_value(
				get_user_meta( $user_id, $meta_key, true ),
				$field,
				'payload'
			);
			$payload[ $field_id ] = $sanitized_value;
		}

		return $payload;
	}

	/**
	 * Build display name for a user
	 *
	 * @param int $user_id User ID.
	 *
	 * @return string
	 */
	public static function build_display_name( int $user_id ): string {
		$user = get_user_by( 'id', $user_id );
		if ( ! $user instanceof WP_User ) {
			return '';
		}

		$first_name = (string) $user->first_name;
		$last_name  = (string) $user->last_name;

		$parts        = array_filter( array( $first_name, $last_name ) );
		$display_name = implode( ' ', $parts );

		if ( '' === $display_name ) {
			$display_name = (string) $user->user_login;
		}

		/**
		 * Filter the formatted display name for an ambassador account.
		 *
		 * @since 0.1.0
		 *
		 * @param string  $display_name Display name.
		 * @param WP_User $user         User object.
		 */
		return (string) apply_filters( 'ambh_account_display_name', $display_name, $user );
	}

	/**
	 * Update the WordPress display name for a user.
	 *
	 * @param int $user_id User ID.
	 *
	 * @return void
	 */
	public static function maybe_update_display_name( int $user_id ): void {

		$display_name = self::build_display_name( $user_id );
		if ( '' === $display_name ) {
			return;
		}

		// Compare with current display name to avoid unnecessary updates.
		$user = get_user_by( 'id', $user_id );
		if ( ! $user instanceof WP_User || $display_name === $user->display_name ) {
			return;
		}

		wp_update_user(
			array(
				'ID'           => $user_id,
				'display_name' => $display_name,
			)
		);
	}

	/**
	 * Render fields based on context.
	 *
	 * @param WP_User|null $user    User object (profile context).
	 * @param string       $context Context.
	 *
	 * @return void
	 */
	private static function render_fields( ?WP_User $user, string $context ): void {
		$fields = self::get_fields( $context );

		foreach ( $fields as $field_id => $field ) {

			$meta_key = $field['meta_key'] ?? '';
			if ( ! $meta_key ) {
				continue;
			}

			$value = '';

			if ( $user instanceof WP_User ) {
				$value = get_user_meta( $user->ID, $meta_key, true );
			}

			self::{"render_{$context}_field"}( $field, $value );
		}
	}

	/**
	 * Render a field in the signup form layout.
	 *
	 * @param string $field_id Field ID.
	 * @param array  $field    Field definition.
	 * @param string $value    Current value.
	 *
	 * @return void
	 */
	private static function render_signup_field( array $field, string|array $value ): void { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed -- signature kept consistent with sibling render_{$context}_field() methods invoked dynamically via self::{"render_{$context}_field"}().

		if ( empty( $field['enable_in_signup'] ) ) {
			return;
		}

		echo '<div class="ambassador-account__form-group">';
		self::render_field_label( $field );
		self::render_field_input( $field, '' );
		echo '</p>';
	}

	/**
	 * Render a field in the profile form layout.
	 *
	 * @param string $field_id Field ID.
	 * @param array  $field    Field definition.
	 * @param string $value    Current value.
	 *
	 * @return void
	 */
	private static function render_profile_field( array $field, string|array $value ): void {

		if ( empty( $field['enable_in_profile'] ) ) {
			return;
		}

		echo '<div class="ambassador-account__form-group">';
		self::render_field_label( $field );
		self::render_field_input( $field, $value );
		echo '</div>';
	}

	private static function render_field_label( array $field ): void {

		$label = $field['label'] ?? '';
		$type  = $field['type'] ?? '';
		$for   = $field['meta_key'] ?? $field['id'] ?? '';

		if ( ! $label ) {
			return;
		}

		$field_types = FieldFactory::get_types();

		if ( ! isset( $field_types[ $type ] ) ) {
			return;
		}

		FieldFactory::create( $type )->render_field_label( $field, $for, $label );
	}

	/**
	 * Render input control for a field.
	 *
	 * @param string $type          Field type.
	 * @param string $id            HTML id attribute.
	 * @param string $name          HTML name attribute.
	 * @param string $value         Field value.
	 * @param string $placeholder   Placeholder text.
	 * @param bool $required        Whether the field is required.
	 * @param array  $field         Field definition.
	 *
	 * @return void
	 */
	private static function render_field_input( array $field, string|array $value ): void {

		$type = $field['type'] ?? '';
		if ( ! $type ) {
			return;
		}

		$field_types = FieldFactory::get_types();
		if ( ! isset( $field_types[ $type ] ) ) {
			return;
		}

		$prefix      = self::FIELD_GROUP;
		$field_id    = $field['meta_key'] ?? $prefix . $field['id'] ?? '';
		$name        = self::FIELD_GROUP . '[' . $field_id . ']';
		$placeholder = $field['placeholder'] ?? '';
		$required    = ! empty( $field['required'] );
		$classes     = $field['input_class'] ?? 'ambassador-account__input';

		FieldFactory::create( $type )->render_field_input(
			$field,
			$field_id,
			$name,
			$value,
			$placeholder,
			$required,
			$classes
		);
	}

	/**
	 * Sanitize field value based on type.
	 *
	 * @param mixed $value Raw value.
	 * @param array $field Field definition.
	 * @param string $context Context of sanitization (save|payload).
	 *
	 * @return string
	 */
	private static function sanitize_field_value( string|array $value, array $field, string $context ): string|array {

		// Sanitize by custom field type
		$type               = $field['type'] ?? 'text';
		$custom_field_types = FieldFactory::get_types();

		if ( isset( $custom_field_types[ $type ] ) ) {
			$value = FieldFactory::create( $type )->sanitize_value( $value );
		} else {
			// Default sanitization for text-based fields.
			$value = sanitize_text_field( $value );
		}

		// Additional context-specific sanitization if needed.
		if ( 'payload' === $context ) {
			return wp_unslash( $value );
		}

		return $value;
	}

	/**
	 * Default field registry.
	 *
	 * @return array<string,array>
	 */
	private static function get_default_fields(): array {
		$fields = array();
		return $fields;
	}
}
