<?php
/**
 * Student Management data and shared services.
 *
 * @package TutorHelper_Bookings
 */

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

/**
 * Provides shared Student Management functionality.
 *
 * WordPress users remain the source of truth for student accounts.
 * Student queries and updates will be added in later migrations.
 */
final class TutorHelper_Students {

	/**
	 * Student Booking Access blocked metadata key.
	 *
	 * @var string
	 */
	const META_BOOKING_BLOCKED =
		'tutorhelper_booking_blocked';

	/**
	 * Student Booking Access message metadata key.
	 *
	 * @var string
	 */
	const META_BOOKING_BLOCKED_MESSAGE =
		'tutorhelper_booking_blocked_message';

	/**
	 * Linked Parent Account user ID metadata key.
	 *
	 * @var string
	 */
	const META_PARENT_USER_ID =
		'tutorhelper_parent_user_id';

	/**
	 * Whether linked Parent Account details override legacy metadata.
	 *
	 * @var string
	 */
	const META_USE_LINKED_PARENT =
		'tutorhelper_use_linked_parent_details';
    
    /**
     * Student WordPress role.
     *
     * @var string
     */
    const STUDENT_ROLE = TutorHelper_Roles::STUDENT_ROLE;

    /**
     * Parent WordPress role.
     *
     * @var string
     */
    const PARENT_ROLE = TutorHelper_Roles::PARENT_ROLE;

    /**
     * Existing parent or guardian name metadata key.
     *
     * @var string
     */
    const META_PARENT_NAME = 'parent_name';

    /**
     * Existing parent or guardian email metadata key.
     *
     * @var string
     */
    const META_PARENT_EMAIL = 'parent_email';

    /**
     * Parent or guardian phone metadata key.
     *
     * @var string
     */
    const META_PARENT_PHONE = 'parent_phone';

    /**
     * Student metadata keys to match fields used in popular plugins (WooCommerce).
     *
     * @var string
     */
    const META_STUDENT_PHONE = 'billing_phone';
    const META_ADDRESS_LINE_1 = 'billing_address_1';
    const META_ADDRESS_LINE_2 = 'billing_address_2';
    const META_ADDRESS_CITY = 'billing_city';
    const META_ADDRESS_COUNTY = 'billing_state';
    const META_ADDRESS_POSTCODE = 'billing_postcode';
    const META_ADDRESS_COUNTRY = 'billing_country';
        
    /**
     * Student date of birth metadata key.
     *
     * Stored in ISO YYYY-MM-DD format.
     *
     * @var string
     */
    const META_DATE_OF_BIRTH =
        'tutorhelper_date_of_birth';


	/**
	 * Initialise shared Student Management services.
	 *
	 * Front-end profile hooks & AJAX hooks
	 *
	 * @return void
	 */
	public static function init() {
		/*
		 * Shared Student Management hooks.
		 */

	}


    /**
     * Retrieve TH Student users.
     *
     * @param array $args Query options.
     *
     * @return array {
     *     Student query result.
     *
     *     @type array $students    WP_User objects.
     *     @type int   $total       Total matching students.
     *     @type int   $total_pages Total pagination pages.
     *     @type int   $page        Current page.
     *     @type int   $per_page    Results per page.
     * }
     */
    public static function get_students( $args = array() ) {
        $args = wp_parse_args(
            $args,
            array(
                'search'   => '',
                'page'     => 1,
                'per_page' => 20,
                'orderby'  => 'display_name',
                'order'    => 'ASC',
            )
        );

        $page = max(
            1,
            absint( $args['page'] )
        );

        $per_page = max(
            1,
            min(
                100,
                absint( $args['per_page'] )
            )
        );

        $search = sanitize_text_field(
            $args['search']
        );

        $query_args = array(
            'role'        => self::STUDENT_ROLE,
            'number'      => $per_page,
            'offset'      => ( $page - 1 ) * $per_page,
            'orderby'     => sanitize_key(
                $args['orderby']
            ),
            'order'       => 'DESC' === strtoupper(
                $args['order']
            )
                ? 'DESC'
                : 'ASC',
            'count_total' => true,
        );

        if ( '' !== $search ) {
            $matching_ids = self::find_student_ids(
                $search
            );

            if ( empty( $matching_ids ) ) {
                return array(
                    'students'    => array(),
                    'total'       => 0,
                    'total_pages' => 0,
                    'page'        => $page,
                    'per_page'    => $per_page,
                );
            }

            $query_args['include'] = $matching_ids;
        }

        $query = new WP_User_Query(
            $query_args
        );

        $total = absint(
            $query->get_total()
        );

        return array(
            'students'    => $query->get_results(),
            'total'       => $total,
            'total_pages' => $total > 0
                ? (int) ceil( $total / $per_page )
                : 0,
            'page'        => $page,
            'per_page'    => $per_page,
        );
    }


    /**
     * Find matching TH Student user IDs.
     *
     * WP_User_Query can search the main users table, but first_name and
     * last_name are stored in user meta. Two ID queries are therefore
     * combined before the final paginated student query is run.
     *
     * @param string $search Search term.
     *
     * @return array
     */
    private static function find_student_ids(
        $search
    ) {
        $search = trim(
            sanitize_text_field( $search )
        );

        if ( '' === $search ) {
            return array();
        }

        $main_query = new WP_User_Query(
            array(
                'role'           => self::STUDENT_ROLE,
                'search'         => '*'
                    . $search
                    . '*',
                'search_columns' => array(
                    'user_login',
                    'user_email',
                    'display_name',
                ),
                'fields'         => 'ID',
                'number'         => -1,
            )
        );

        $meta_query = new WP_User_Query(
            array(
                'role'       => self::STUDENT_ROLE,
                'fields'     => 'ID',
                'number'     => -1,
                'meta_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- First and last names are stored in usermeta, so this bounded student-name search intentionally uses WP_User_Query meta conditions.
                    'relation' => 'OR',
                    array(
                        'key'     => 'first_name',
                        'value'   => $search,
                        'compare' => 'LIKE',
                    ),
                    array(
                        'key'     => 'last_name',
                        'value'   => $search,
                        'compare' => 'LIKE',
                    ),
                ),
            )
        );

        return array_values(
            array_unique(
                array_map(
                    'absint',
                    array_merge(
                        $main_query->get_results(),
                        $meta_query->get_results()
                    )
                )
            )
        );
    }


    /**
     * Retrieve one TH Student user.
     *
     * @param int $student_user_id Student WordPress user ID.
     *
     * @return WP_User|null
     */
    public static function get_student(
        $student_user_id
    ) {
        $student_user_id = absint(
            $student_user_id
        );

        if ( ! $student_user_id ) {
            return null;
        }

        $user = get_userdata(
            $student_user_id
        );

        if (
            ! $user instanceof WP_User
            || ! in_array(
                self::STUDENT_ROLE,
                (array) $user->roles,
                true
            )
        ) {
            return null;
        }

        return $user;
    }


    /**
     * Return a short parent or guardian summary.
     *
     * @param int $student_user_id Student WordPress user ID.
     *
     * @return array
     */
    public static function get_parent_summary(
        $student_user_id
    ) {
        $parent = self::get_parent_details(
            $student_user_id
        );

        return array(
            'name'  => $parent['name'],
            'email' => $parent['email'],
        );
    }
    


    /**
     * Return parent or guardian details for a student.
     *
     * Separately stored parent metadata remains available as a fallback.
     * When a Parent Account is linked and override is enabled, the linked
     * WordPress account supplies the displayed name, email and phone.
     *
     * @param int $student_user_id Student WordPress user ID.
     *
     * @return array
     */
    public static function get_parent_details(
        $student_user_id
    ) {
        $student_user_id = absint(
            $student_user_id
        );

        $linked_parent_user_id = absint(
            get_user_meta(
                $student_user_id,
                self::META_PARENT_USER_ID,
                true
            )
        );

        $use_linked_parent = 1 === absint(
            get_user_meta(
                $student_user_id,
                self::META_USE_LINKED_PARENT,
                true
            )
        );

        $legacy_name = sanitize_text_field(
            get_user_meta(
                $student_user_id,
                self::META_PARENT_NAME,
                true
            )
        );

        $legacy_email = sanitize_email(
            get_user_meta(
                $student_user_id,
                self::META_PARENT_EMAIL,
                true
            )
        );

        $legacy_phone = sanitize_text_field(
            get_user_meta(
                $student_user_id,
                self::META_PARENT_PHONE,
                true
            )
        );

        $linked_parent = $linked_parent_user_id
            ? get_userdata(
                $linked_parent_user_id
            )
            : null;

        if ( ! $linked_parent instanceof WP_User ) {
            $linked_parent = null;
            $linked_parent_user_id = 0;
            $use_linked_parent = false;
        }

        $linked_name = '';
        $linked_email = '';
        $linked_phone = '';

        if ( $linked_parent ) {
            $linked_name = $linked_parent->display_name;
            $linked_email = $linked_parent->user_email;

            $linked_phone = sanitize_text_field(
                get_user_meta(
                    $linked_parent->ID,
                    'billing_phone',
                    true
                )
            );
        }

        return array(
            'name' => $use_linked_parent
                ? $linked_name
                : $legacy_name,

            'email' => $use_linked_parent
                ? $linked_email
                : $legacy_email,

            'phone' => $use_linked_parent
                ? $linked_phone
                : $legacy_phone,

            'legacy_name'  => $legacy_name,
            'legacy_email' => $legacy_email,
            'legacy_phone' => $legacy_phone,

            'linked_parent_user_id' =>
                $linked_parent_user_id,

            'linked_parent' =>
                $linked_parent,

            'linked_name' =>
                $linked_name,

            'linked_email' =>
                $linked_email,

            'linked_phone' =>
                $linked_phone,

            'use_linked_parent' =>
                $use_linked_parent,
        );
    }



    /**
     * Search WordPress users who may be linked as Parent Accounts.
     *
     * This searches all WordPress accounts, regardless of their current
     * role. The TH Parent role is added later when the account is linked
     * and the student form is saved.
     *
     * @param string $search          Name, username or email search.
     * @param int    $student_user_id Student user to exclude.
     * @param int    $limit           Maximum result count.
     *
     * @return array
     */
    public static function search_parent_accounts(
        $search,
        $student_user_id = 0,
        $limit = 20
    ) {
        $search = trim(
            sanitize_text_field( $search )
        );

        $student_user_id = absint(
            $student_user_id
        );

        $limit = max(
            1,
            min(
                50,
                absint( $limit )
            )
        );

        if ( strlen( $search ) < 2 ) {
            return array();
        }

        $query_args = array(
            'search' => '*'
                . $search
                . '*',

            'search_columns' => array(
                'user_login',
                'user_email',
                'display_name',
            ),

            'number'      => $limit,
            'orderby'     => 'display_name',
            'order'       => 'ASC',
            'count_total' => false,
        );

        if ( $student_user_id ) {
            $query_args['exclude'] = array( // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_exclude -- Excluding the current student prevents a user being linked as their own Parent Account.
                $student_user_id,
            );
        }

        $query = new WP_User_Query(
            $query_args
        );

        $users = $query->get_results();

        /*
        * First and last names are stored in user metadata rather than
        * the main WordPress users table. Search them separately when
        * the main query has not filled the result limit.
        */
        if ( count( $users ) < $limit ) {
            $existing_ids = array_map(
                'absint',
                wp_list_pluck(
                    $users,
                    'ID'
                )
            );

            $exclude_ids = $existing_ids;

            if ( $student_user_id ) {
                $exclude_ids[] =
                    $student_user_id;
            }

            $remaining = $limit
                - count( $users );

            $meta_query_args = array(
                'number'      => $remaining,
                'orderby'     => 'display_name',
                'order'       => 'ASC',
                'count_total' => false,

                'meta_query' => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- Parent Account fallback search must query first_name and last_name in usermeta and is bounded by the remaining result limit.
                    'relation' => 'OR',

                    array(
                        'key'     => 'first_name',
                        'value'   => $search,
                        'compare' => 'LIKE',
                    ),

                    array(
                        'key'     => 'last_name',
                        'value'   => $search,
                        'compare' => 'LIKE',
                    ),
                ),
            );

            if ( ! empty( $exclude_ids ) ) {
                $meta_query_args['exclude'] = // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_exclude -- Excluding IDs already returned prevents duplicates in the bounded fallback Parent Account search.
                    array_values(
                        array_unique(
                            $exclude_ids
                        )
                    );
            }

            $meta_query = new WP_User_Query(
                $meta_query_args
            );

            $users = array_merge(
                $users,
                $meta_query->get_results()
            );
        }

        return array_slice(
            $users,
            0,
            $limit
        );
    }


    /**
     * Update the Parent Account linked to a student.
     *
     * Existing user roles are preserved. Unlinking does not remove the
     * TH Parent role because the account may remain linked to another
     * student.
     *
     * @param int  $student_user_id Student WordPress user ID.
     * @param int  $parent_user_id  Parent WordPress user ID or zero.
     * @param bool $use_linked      Whether linked details override legacy data.
     *
     * @return true|WP_Error
     */
    public static function update_parent_link(
        $student_user_id,
        $parent_user_id,
        $use_linked
    ) {
        $student = self::get_student(
            $student_user_id
        );

        if ( ! $student ) {
            return new WP_Error(
                'tutorhelper_student_not_found',
                __(
                    'The student account could not be found.',
                    'tutorhelper-bookings'
                )
            );
        }

        $student_user_id = absint(
            $student_user_id
        );

        $parent_user_id = absint(
            $parent_user_id
        );

        $old_parent_user_id = absint(
            get_user_meta(
                $student_user_id,
                self::META_PARENT_USER_ID,
                true
            )
        );

        $old_use_linked = 1 === absint(
            get_user_meta(
                $student_user_id,
                self::META_USE_LINKED_PARENT,
                true
            )
        );

        if ( $parent_user_id ) {
            if ( $parent_user_id === $student_user_id ) {
                return new WP_Error(
                    'tutorhelper_parent_same_as_student',
                    __(
                        'A student cannot be linked as their own Parent Account.',
                        'tutorhelper-bookings'
                    )
                );
            }

            $parent_user = get_userdata(
                $parent_user_id
            );

            if ( ! $parent_user instanceof WP_User ) {
                return new WP_Error(
                    'tutorhelper_parent_not_found',
                    __(
                        'The selected Parent Account could not be found.',
                        'tutorhelper-bookings'
                    )
                );
            }

            if (
                ! in_array(
                    self::PARENT_ROLE,
                    (array) $parent_user->roles,
                    true
                )
            ) {
                $parent_user->add_role(
                    self::PARENT_ROLE
                );

                TutorHelper_Student_Audit_Log::record(
                    $student_user_id,
                    'parent_role_added',
                    'parent_user_id',
                    '',
                    $parent_user_id
                );
            }

            update_user_meta(
                $student_user_id,
                self::META_PARENT_USER_ID,
                $parent_user_id
            );

            update_user_meta(
                $student_user_id,
                self::META_USE_LINKED_PARENT,
                $use_linked ? 1 : 0
            );
        } else {
            delete_user_meta(
                $student_user_id,
                self::META_PARENT_USER_ID
            );

            delete_user_meta(
                $student_user_id,
                self::META_USE_LINKED_PARENT
            );

            $use_linked = false;
        }

        if ( $old_parent_user_id !== $parent_user_id ) {
            TutorHelper_Student_Audit_Log::record(
                $student_user_id,
                $parent_user_id
                    ? 'parent_account_linked'
                    : 'parent_account_unlinked',
                'parent_user_id',
                $old_parent_user_id,
                $parent_user_id
            );
        }

        if (
            $old_use_linked
            !== (bool) $use_linked
        ) {
            TutorHelper_Student_Audit_Log::record(
                $student_user_id,
                'parent_detail_override_updated',
                'use_linked_parent',
                $old_use_linked,
                (bool) $use_linked
            );
        }

        return true;
    }






    /**
     * Return whether a student is blocked from booking.
     *
     * @param int $student_user_id Student WordPress user ID.
     *
     * @return bool
     */
    public static function is_booking_blocked(
        $student_user_id
    ) {
        return 1 === absint(
            get_user_meta(
                absint( $student_user_id ),
                self::META_BOOKING_BLOCKED,
                true
            )
        );
    }


    /**
     * Return display information for one student.
     *
     * This method gathers WordPress user fields and TutorHelper metadata
     * into one consistent structure for admin and frontend views.
     *
     * @param WP_User|int $student Student user or user ID.
     *
     * @return array|null
     */
    public static function get_student_details(
        $student
    ) {
        if ( is_numeric( $student ) ) {
            $student = self::get_student(
                absint( $student )
            );
        }

        if ( ! $student instanceof WP_User ) {
            return null;
        }

        $student_user_id = absint(
            $student->ID
        );

        $first_name = sanitize_text_field(
            get_user_meta(
                $student_user_id,
                'first_name',
                true
            )
        );

        $last_name = sanitize_text_field(
            get_user_meta(
                $student_user_id,
                'last_name',
                true
            )
        );

        $student_name = trim(
            $first_name . ' ' . $last_name
        );

        if ( '' === $student_name ) {
            $student_name = $student->display_name;
        }

        return array(
            'id'           => $student_user_id,
            'student_name' => $student_name,
            'display_name' => $student->display_name,
            'first_name'   => $first_name,
            'last_name'    => $last_name,
            'username'     => $student->user_login,
            'email'        => $student->user_email,
            'phone'        => sanitize_text_field(
                get_user_meta(
                    $student_user_id,
                    self::META_STUDENT_PHONE,
                    true
                )
            ),
            'registered'   => $student->user_registered,
            'roles'        => array_values(
                (array) $student->roles
            ),
            'booking'      => array(
                'blocked' => self::is_booking_blocked(
                    $student_user_id
                ),
                'message' => sanitize_textarea_field(
                    get_user_meta(
                        $student_user_id,
                        self::META_BOOKING_BLOCKED_MESSAGE,
                        true
                    )
                ),
            ),
            'parent'       => self::get_parent_details(
                $student_user_id
            ),
            'address'      => self::get_postal_address(
                $student_user_id
            ),
        );
    }


    /**
     * Return a student's stored postal address.
     *
     * @param int $student_user_id Student WordPress user ID.
     *
     * @return array
     */
    public static function get_postal_address(
        $student_user_id
    ) {
        $student_user_id = absint(
            $student_user_id
        );

        $address = array(
            'line_1' => sanitize_text_field(
                get_user_meta(
                    $student_user_id,
                    self::META_ADDRESS_LINE_1,
                    true
                )
            ),
            'line_2' => sanitize_text_field(
                get_user_meta(
                    $student_user_id,
                    self::META_ADDRESS_LINE_2,
                    true
                )
            ),
            'city' => sanitize_text_field(
                get_user_meta(
                    $student_user_id,
                    self::META_ADDRESS_CITY,
                    true
                )
            ),
            'county' => sanitize_text_field(
                get_user_meta(
                    $student_user_id,
                    self::META_ADDRESS_COUNTY,
                    true
                )
            ),
            'postcode' => sanitize_text_field(
                get_user_meta(
                    $student_user_id,
                    self::META_ADDRESS_POSTCODE,
                    true
                )
            ),
            'country' => sanitize_text_field(
                get_user_meta(
                    $student_user_id,
                    self::META_ADDRESS_COUNTRY,
                    true
                )
            ),
        );

        $address['lines'] = array_values(
            array_filter(
                array(
                    $address['line_1'],
                    $address['line_2'],
                    $address['city'],
                    $address['county'],
                    $address['postcode'],
                    $address['country'],
                ),
                static function ( $value ) {
                    return '' !== trim(
                        (string) $value
                    );
                }
            )
        );

        $address['is_empty'] = empty(
            $address['lines']
        );

        return $address;
    }



    /**
     * Return editable student metadata definitions.
     *
     * @return array
     */
    public static function get_editable_meta_fields() {
        // phpcs:disable WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- The following meta_key entries are field-definition metadata, not WP_Query arguments or database queries.
        $fields = array(
            'first_name' => array(
                'meta_key' => 'first_name',
                'type'     => 'text',
            ),

            'last_name' => array(
                'meta_key' => 'last_name',
                'type'     => 'text',
            ),

            'phone' => array(
                'meta_key' =>
                    self::META_STUDENT_PHONE,
                'type'     => 'text',
            ),

            'parent_name' => array(
                'meta_key' =>
                    self::META_PARENT_NAME,
                'type'     => 'text',
            ),

            'parent_email' => array(
                'meta_key' =>
                    self::META_PARENT_EMAIL,
                'type'     => 'email',
            ),

            'parent_phone' => array(
                'meta_key' =>
                    self::META_PARENT_PHONE,
                'type'     => 'text',
            ),

            'address_line_1' => array(
                'meta_key' =>
                    self::META_ADDRESS_LINE_1,
                'type'     => 'text',
            ),

            'address_line_2' => array(
                'meta_key' =>
                    self::META_ADDRESS_LINE_2,
                'type'     => 'text',
            ),

            'address_city' => array(
                'meta_key' =>
                    self::META_ADDRESS_CITY,
                'type'     => 'text',
            ),

            'address_county' => array(
                'meta_key' =>
                    self::META_ADDRESS_COUNTY,
                'type'     => 'text',
            ),

            'address_postcode' => array(
                'meta_key' =>
                    self::META_ADDRESS_POSTCODE,
                'type'     => 'text',
            ),

            'address_country' => array(
                'meta_key' =>
                    self::META_ADDRESS_COUNTRY,
                'type'     => 'text',
            ),
        );
    // phpcs:enable WordPress.DB.SlowDBQuery.slow_db_query_meta_key

    return $fields;
}


    /**
     * Update editable student account details.
     *
     * @param int   $student_user_id Student WordPress user ID.
     * @param array $data            Submitted values.
     *
     * @return true|WP_Error
     */
    public static function update_student(
        $student_user_id,
        $data
    ) {
        $student = self::get_student(
            $student_user_id
        );

        if ( ! $student ) {
            return new WP_Error(
                'tutorhelper_student_not_found',
                __(
                    'The student account could not be found.',
                    'tutorhelper-bookings'
                )
            );
        }

        if ( ! is_array( $data ) ) {
            return new WP_Error(
                'tutorhelper_student_invalid_data',
                __(
                    'The submitted student details are invalid.',
                    'tutorhelper-bookings'
                )
            );
        }

        $email = isset( $data['user_email'] )
            ? sanitize_email(
                $data['user_email']
            )
            : '';

        if (
            '' === $email
            || ! is_email( $email )
        ) {
            return new WP_Error(
                'tutorhelper_student_invalid_email',
                __(
                    'Enter a valid student email address.',
                    'tutorhelper-bookings'
                )
            );
        }

        $email_owner = email_exists(
            $email
        );

        if (
            $email_owner
            && absint( $email_owner )
                !== absint( $student_user_id )
        ) {
            return new WP_Error(
                'tutorhelper_student_email_exists',
                __(
                    'That email address is already used by another WordPress account.',
                    'tutorhelper-bookings'
                )
            );
        }

        $display_name = isset(
            $data['display_name']
        )
            ? sanitize_text_field(
                $data['display_name']
            )
            : '';

        if ( '' === $display_name ) {
            return new WP_Error(
                'tutorhelper_student_display_name_required',
                __(
                    'Enter a display name for the student.',
                    'tutorhelper-bookings'
                )
            );
        }

        $wp_result = wp_update_user(
            array(
                'ID'           =>
                    absint( $student_user_id ),

                'user_email'   => $email,

                'display_name' =>
                    $display_name,
            )
        );

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

        self::audit_change(
            $student_user_id,
            'user_email',
            $student->user_email,
            $email
        );

        self::audit_change(
            $student_user_id,
            'display_name',
            $student->display_name,
            $display_name
        );

        foreach (
            self::get_editable_meta_fields()
            as $field_key => $definition
        ) {
            $new_value = isset(
                $data[ $field_key ]
            )
                ? self::sanitize_field_value(
                    $data[ $field_key ],
                    $definition['type']
                )
                : '';

            $meta_key =
                $definition['meta_key'];

            $old_value = get_user_meta(
                $student_user_id,
                $meta_key,
                true
            );

            if ( $old_value === $new_value ) {
                continue;
            }

            update_user_meta(
                $student_user_id,
                $meta_key,
                $new_value
            );

            TutorHelper_Student_Audit_Log::record(
                $student_user_id,
                'student_details_updated',
                $field_key,
                $old_value,
                $new_value
            );
        }

        return true;
    }


    /**
     * Sanitize an editable student field.
     *
     * @param mixed  $value Value.
     * @param string $type  Field type.
     *
     * @return string
     */
    private static function sanitize_field_value(
        $value,
        $type
    ) {
        if ( 'email' === $type ) {
            return sanitize_email(
                $value
            );
        }

        if ( 'textarea' === $type ) {
            return sanitize_textarea_field(
                $value
            );
        }

        return sanitize_text_field(
            $value
        );
    }


    /**
     * Record a changed value only when it differs.
     *
     * @param int    $student_user_id Student user ID.
     * @param string $field_key       Field key.
     * @param mixed  $old_value       Old value.
     * @param mixed  $new_value       New value.
     *
     * @return void
     */
    private static function audit_change(
        $student_user_id,
        $field_key,
        $old_value,
        $new_value
    ) {
        if (
            (string) $old_value
            === (string) $new_value
        ) {
            return;
        }

        TutorHelper_Student_Audit_Log::record(
            $student_user_id,
            'student_details_updated',
            $field_key,
            $old_value,
            $new_value
        );
    }


    /**
     * Update a student's Booking Access settings.
     *
     * @param int    $student_user_id Student user ID.
     * @param bool   $blocked         Whether booking is blocked.
     * @param string $message         Student-facing message.
     *
     * @return true|WP_Error
     */
    public static function update_booking_access(
        $student_user_id,
        $blocked,
        $message
    ) {
        $student = self::get_student(
            $student_user_id
        );

        if ( ! $student ) {
            return new WP_Error(
                'tutorhelper_student_not_found',
                __(
                    'The student account could not be found.',
                    'tutorhelper-bookings'
                )
            );
        }

        $blocked = (bool) $blocked;

        $message = sanitize_textarea_field(
            $message
        );

        if (
            $blocked
            && '' === $message
        ) {
            $message = __(
                'Online booking is temporarily unavailable. Please contact us.',
                'tutorhelper-bookings'
            );
        }

        $old_blocked =
            self::is_booking_blocked(
                $student_user_id
            );

        $old_message = get_user_meta(
            $student_user_id,
            self::META_BOOKING_BLOCKED_MESSAGE,
            true
        );

        update_user_meta(
            $student_user_id,
            self::META_BOOKING_BLOCKED,
            $blocked ? 1 : 0
        );

        update_user_meta(
            $student_user_id,
            self::META_BOOKING_BLOCKED_MESSAGE,
            $message
        );

        if ( $old_blocked !== $blocked ) {
            TutorHelper_Student_Audit_Log::record(
                $student_user_id,
                $blocked
                    ? 'booking_access_blocked'
                    : 'booking_access_restored',
                'booking_blocked',
                $old_blocked,
                $blocked
            );
        }

        if (
            (string) $old_message
            !== (string) $message
        ) {
            TutorHelper_Student_Audit_Log::record(
                $student_user_id,
                'booking_access_message_updated',
                'booking_blocked_message',
                $old_message,
                $message
            );
        }

        return true;
    }




}
