<?php
/**
 * User repository
 *
 * @package NemtlyBooking
 */

namespace NemtlyBooking\Repositories;

use NemtlyBooking\Models\Booking;

/**
 * User Repository class
 *
 * Abstracts user data access and management
 *
 * @since PBOOKING_SINCE
 */
class User_Repository {

    /**
     * Constructor
     */
    public function __construct() {
        // No initialization needed
    }

    /**
     * Find user by ID
     *
     * @param int $user_id The user ID to find.
     * @return \WP_User|null
     */
    public function find( $user_id ) {
        $user = get_user_by( 'ID', $user_id );
        return $user ? $user : null;
    }

    /**
     * Find user by email
     *
     * @param string $email The user email to find.
     * @return \WP_User|null
     */
    public function find_by_email( $email ) {
        $user = get_user_by( 'email', $email );
        return $user ? $user : null;
    }

    /**
     * Find user by username
     *
     * @param string $username The username to find.
     * @return \WP_User|null
     */
    public function find_by_username( $username ) {
        $user = get_user_by( 'login', $username );
        return $user ? $user : null;
    }

    /**
     * Get current user
     *
     * @return \WP_User|null
     */
    public function get_current_user() {
        $user_id = get_current_user_id();
        return $user_id ? $this->find( $user_id ) : null;
    }

    /**
     * Get user booking history
     *
     * @param int $user_id The user ID.
     * @param array $args Query arguments.
     * @return array
     */
    public function get_user_booking_history( $user_id, $args = [] ) {
        $default_args = [
            'per_page'  => 10,
            'page'      => 1,
            'status'    => '',
            'date_from' => '',
            'date_to'   => '',
        ];

        $args = wp_parse_args( $args, $default_args );

        // Get bookings for this user
        $booking_repository = new Booking_Repository();
        $bookings           = $booking_repository->find_by_user_id( $user_id );

        // Filter by status if specified
        if ( ! empty( $args['status'] ) ) {
            $bookings = array_filter(
                $bookings,
                function ( $booking ) use ( $args ) {
					return $booking->get_booking_status() === $args['status'];
				}
            );
        }

        // Filter by date range if specified
        if ( ! empty( $args['date_from'] ) || ! empty( $args['date_to'] ) ) {
            $bookings = array_filter(
                $bookings,
                function ( $booking ) use ( $args ) {
					$booking_date = $booking->get_booking_date();
					if ( ! $booking_date ) {
						return true;
					}

					$booking_timestamp = strtotime( $booking_date );

					if ( ! empty( $args['date_from'] ) ) {
						$from_timestamp = strtotime( $args['date_from'] );
						if ( $booking_timestamp < $from_timestamp ) {
							return false;
						}
					}

					if ( ! empty( $args['date_to'] ) ) {
						$to_timestamp = strtotime( $args['date_to'] );
						if ( $booking_timestamp > $to_timestamp ) {
							return false;
						}
					}

					return true;
				}
            );
        }

        // Apply pagination
        $total_bookings = count( $bookings );
        $offset         = ( $args['page'] - 1 ) * $args['per_page'];
        $bookings       = array_slice( $bookings, $offset, $args['per_page'] );

        return [
            'bookings'     => $bookings,
            'total'        => $total_bookings,
            'pages'        => ceil( $total_bookings / $args['per_page'] ),
            'current_page' => $args['page'],
        ];
    }

    /**
     * Get user booking statistics
     *
     * @param int $user_id The user ID.
     * @return array
     */
    public function get_user_booking_statistics( $user_id ) {
        $booking_repository = new Booking_Repository();
        $bookings           = $booking_repository->find_by_user_id( $user_id );

        $stats = [
            'total_bookings'      => count( $bookings ),
            'pending_bookings'    => 0,
            'confirmed_bookings'  => 0,
            'cancelled_bookings'  => 0,
            'waitlisted_bookings' => 0,
            'upcoming_bookings'   => 0,
            'past_bookings'       => 0,
        ];

        $current_time = current_time( 'timestamp' );

        foreach ( $bookings as $booking ) {
            $status       = $booking->get_booking_status();
            $booking_date = $booking->get_booking_date();

            // Count by status
            switch ( $status ) {
                case 'pending':
                    ++$stats['pending_bookings'];
                    break;
                case 'confirmed':
                    ++$stats['confirmed_bookings'];
                    break;
                case 'cancelled':
                    ++$stats['cancelled_bookings'];
                    break;
                case 'waitlisted':
                    ++$stats['waitlisted_bookings'];
                    break;
            }

            // Count by date
            if ( $booking_date ) {
                $booking_timestamp = strtotime( $booking_date );
                if ( $booking_timestamp > $current_time ) {
                    ++$stats['upcoming_bookings'];
                } else {
                    ++$stats['past_bookings'];
                }
            }
        }

        return $stats;
    }

    /**
     * Get user preferences
     *
     * @param int $user_id The user ID.
     * @return array
     */
    public function get_user_preferences( $user_id ) {
        $preferences = get_user_meta( $user_id, 'nemtly_booking_preferences', true );
        return is_array( $preferences ) ? $preferences : [];
    }

    /**
     * Update user preferences
     *
     * @param int   $user_id     The user ID.
     * @param array $preferences The preferences to update.
     * @return bool
     */
    public function update_user_preferences( $user_id, $preferences ) {
        $existing_preferences = $this->get_user_preferences( $user_id );
        $updated_preferences  = array_merge( $existing_preferences, $preferences );

        return update_user_meta( $user_id, 'nemtly_booking_preferences', $updated_preferences );
    }

    /**
     * Check if user has booking capability
     *
     * @param int $user_id The user ID.
     * @return bool
     */
    public function can_book( $user_id ) {
        $user = $this->find( $user_id );
        if ( ! $user ) {
            return false;
        }

        // Check if user is blocked
        $is_blocked = get_user_meta( $user_id, 'nemtly_booking_blocked', true );
        if ( $is_blocked ) {
            return false;
        }

        // Check user role permissions
        $allowed_roles = apply_filters( 'nemtly_booking_allowed_roles', [ 'subscriber', 'customer', 'administrator', 'editor' ] );
        $user_roles    = $user->roles;

        foreach ( $user_roles as $role ) {
            if ( in_array( $role, $allowed_roles, true ) ) {
                return true;
            }
        }

        return false;
    }

    /**
     * Block user from booking
     *
     * @param int $user_id The user ID.
     * @return bool
     */
    public function block_user( $user_id ) {
        return update_user_meta( $user_id, 'nemtly_booking_blocked', true );
    }

    /**
     * Unblock user from booking
     *
     * @param int $user_id The user ID.
     * @return bool
     */
    public function unblock_user( $user_id ) {
        return delete_user_meta( $user_id, 'nemtly_booking_blocked' );
    }

    /**
     * Check if user is blocked
     *
     * @param int $user_id The user ID.
     * @return bool
     */
    public function is_user_blocked( $user_id ) {
        return (bool) get_user_meta( $user_id, 'nemtly_booking_blocked', true );
    }

    /**
     * Get users with booking history
     *
     * @param array $args Query arguments.
     * @return array
     */
    public function get_users_with_bookings( $args = [] ) {
        $default_args = [
            'per_page' => 10,
            'page'     => 1,
            'search'   => '',
            'role'     => '',
        ];

        $args = wp_parse_args( $args, $default_args );

        // Get all users who have made bookings
        $booking_repository = new Booking_Repository();
        $all_bookings       = $booking_repository->find_all();

        $user_ids = [];
        foreach ( $all_bookings as $booking ) {
            $user_id = $booking->get_user_id();
            if ( $user_id && ! in_array( $user_id, $user_ids, true ) ) {
                $user_ids[] = $user_id;
            }
        }

        // Filter by search term
        if ( ! empty( $args['search'] ) ) {
            $user_ids = array_filter(
                $user_ids,
                function ( $user_id ) use ( $args ) {
					$user = $this->find( $user_id );
					if ( ! $user ) {
						return false;
					}

					$search_term = strtolower( $args['search'] );
					$user_name   = strtolower( $user->display_name );
					$user_email  = strtolower( $user->user_email );

					return strpos( $user_name, $search_term ) !== false ||
                        strpos( $user_email, $search_term ) !== false;
				}
            );
        }

        // Filter by role
        if ( ! empty( $args['role'] ) ) {
            $user_ids = array_filter(
                $user_ids,
                function ( $user_id ) use ( $args ) {
					$user = $this->find( $user_id );
					if ( ! $user ) {
						return false;
					}

					return in_array( $args['role'], $user->roles, true );
				}
            );
        }

        // Apply pagination
        $total_users = count( $user_ids );
        $offset      = ( $args['page'] - 1 ) * $args['per_page'];
        $user_ids    = array_slice( $user_ids, $offset, $args['per_page'] );

        // Get user objects
        $users = [];
        foreach ( $user_ids as $user_id ) {
            $user = $this->find( $user_id );
            if ( $user ) {
                $users[] = $user;
            }
        }

        return [
            'users'        => $users,
            'total'        => $total_users,
            'pages'        => ceil( $total_users / $args['per_page'] ),
            'current_page' => $args['page'],
        ];
    }

    /**
     * Get user booking count
     *
     * @param int $user_id The user ID.
     * @return int
     */
    public function get_user_booking_count( $user_id ) {
        $booking_repository = new Booking_Repository();
        $bookings           = $booking_repository->find_by_user_id( $user_id );
        return count( $bookings );
    }

    /**
     * Get user's favorite events
     *
     * @param int $user_id The user ID.
     * @return array
     */
    public function get_user_favorite_events( $user_id ) {
        $favorites = get_user_meta( $user_id, 'nemtly_booking_favorite_events', true );
        return is_array( $favorites ) ? $favorites : [];
    }

    /**
     * Add event to user favorites
     *
     * @param int $user_id  The user ID.
     * @param int $event_id The event ID.
     * @return bool
     */
    public function add_favorite_event( $user_id, $event_id ) {
        $favorites = $this->get_user_favorite_events( $user_id );

        if ( ! in_array( $event_id, $favorites, true ) ) {
            $favorites[] = $event_id;
            return update_user_meta( $user_id, 'nemtly_booking_favorite_events', $favorites );
        }

        return true;
    }

    /**
     * Remove event from user favorites
     *
     * @param int $user_id  The user ID.
     * @param int $event_id The event ID.
     * @return bool
     */
    public function remove_favorite_event( $user_id, $event_id ) {
        $favorites = $this->get_user_favorite_events( $user_id );
        $favorites = array_diff( $favorites, [ $event_id ] );

        return update_user_meta( $user_id, 'nemtly_booking_favorite_events', array_values( $favorites ) );
    }

    /**
     * Check if event is in user favorites
     *
     * @param int $user_id  The user ID.
     * @param int $event_id The event ID.
     * @return bool
     */
    public function is_favorite_event( $user_id, $event_id ) {
        $favorites = $this->get_user_favorite_events( $user_id );
        return in_array( $event_id, $favorites, true );
    }
}
