<?php

namespace RadiusTheme\RadiusBooking\Services;

use RadiusTheme\RadiusBooking\Core\Container\Container;
use RadiusTheme\RadiusBooking\Core\Support\Collection;
use RadiusTheme\RadiusBooking\Models\User;
use RadiusTheme\RadiusBooking\Models\UserProfile;
use RadiusTheme\RadiusBooking\Repositories\EmployeeRepository;
use RadiusTheme\RadiusBooking\Repositories\UserProfileRepository;
use RadiusTheme\RadiusBooking\Repositories\UserRepository;
use function Avifinfo\read;

/**
 * Business logic layer for Employee Panel.
 */
class EmployeePanelService {

	private UserRepository $userRepo;

	private EmployeeRepository $employeeRepo;

	/**
	 * Constructor.
	 *
	 * @param UserRepository $userRepo User repository instance.
	 * @param EmployeeRepository $employeeRepo Employee repository instance.
	 */
	public function __construct( UserRepository $userRepo, EmployeeRepository $employeeRepo ) {
		$this->userRepo     = $userRepo;
		$this->employeeRepo = $employeeRepo;
	}

	/**
	 * Get comprehensive dashboard data for an employee.
	 *
	 * @param int $employee_id Employee ID.
	 * @param int $appointments_page Page number for appointments.
	 * @param int $appointments_per_page Items per page for appointments.
	 * @param int $clients_page Page number for clients.
	 * @param int $clients_per_page Items per page for clients.
	 *
	 * @return array Dashboard data including stats, appointments, clients, and services.
	 */
	public function getDashboardData( $employee_id ) {
		$employee = $this->employeeRepo->find( $employee_id );

		if ( ! $employee ) {
			return array(
				'success' => false,
				'message' => __( 'Employee not found.', 'radius-booking' ),
			);
		}

		$today = wp_date( 'Y-m-d' );

		// In Classified Listing staff mode each listing creates its own employee.
		// One WP user with multiple listings ends up with multiple employee_ids,
		// each holding a different service. Resolve all of them so every count
		// / list / aggregate covers the WP user as a whole, not just one shard.
		$ids = $this->getRelatedEmployeeIds( $employee_id );

		$stats              = array(
			'today_appointments'     => $this->employeeRepo->getTodayAppointmentCount( $ids, $today ),
			'total_completed'        => $this->employeeRepo->getCompletedAppointmentCount( $ids ),
			'total_active_clients'   => $this->employeeRepo->getActiveClientCount( $ids ),
			'total_earnings'         => $this->employeeRepo->getTotalEarnings( $ids ),
			'pending_appointments'   => $this->employeeRepo->getPendingAppointmentCount( $ids ),
			'cancelled_appointments' => $this->employeeRepo->getCancelledAppointmentCount( $ids ),
		);
		$services           = $this->getAggregatedServicesForEmployee( $employee_id );
		$today_appointments = $this->employeeRepo->getTodayAppointments( $ids, $today );

		$today_list = array_map(
			function ( $appointment ) {
				return apply_filters( 'rtrb_my_booking_item_data', (object) $appointment );
			},
			is_array( $today_appointments ) ? $today_appointments : $today_appointments->toArray()
		);

		return array(
			'success'            => true,
			'stats'              => $stats,
			'today_appointments' => $today_list,
			'services'           => $services,
		);
	}

	/**
	 * Resolve the set of employee_ids that should appear in this dashboard.
	 *
	 * Aggregates every UserProfile that shares the same wp_user_id as the
	 * primary profile. That covers:
	 *   - Staff-mode listing-tied profiles (one per CL listing).
	 *   - The service-mode author profile (no listing_id).
	 *   - Any other profile the same WP user owns.
	 *
	 * Profiles without a wp_user_id (manually-created radius_booking employees)
	 * fall through to [$employee_id].
	 *
	 * @param int $employee_id Primary employee id from the request.
	 *
	 * @return int[]
	 */
	public function getRelatedEmployeeIds( int $employee_id ): array {
		$primary_profile = UserProfile::where( 'user_id', $employee_id )->first();
		$wp_user_id      = $primary_profile ? (int) $primary_profile->wp_user_id : 0;

		if ( ! $wp_user_id ) {
			return array( $employee_id );
		}

		$sibling_profiles = UserProfile::where( 'wp_user_id', $wp_user_id )->get();

		$ids = array( $employee_id );
		foreach ( $sibling_profiles as $row ) {
			$ids[] = (int) $row->user_id;
		}
		return array_values( array_unique( array_filter( $ids ) ) );
	}

	/**
	 * Aggregate EmployeeService rows across the WP user's sibling listing-tied
	 * employees, deduped by EmployeeService.id.
	 *
	 * @param int $employee_id Primary employee id from the dashboard request.
	 *
	 * @return array Service rows.
	 */
	private function getAggregatedServicesForEmployee( int $employee_id ): array {
		$ids = $this->getRelatedEmployeeIds( $employee_id );
		if ( count( $ids ) === 1 ) {
			return $this->userRepo->getUserServices( $ids[0] );
		}

		// Dedup by service_id: two sibling employees can each have an
		// EmployeeService row pointing at the same service (e.g. two listings
		// under the same form/service), and the user should only see that
		// service once in their list.
		$services = array();
		$seen     = array();
		foreach ( $ids as $uid ) {
			foreach ( $this->userRepo->getUserServices( $uid ) as $svc ) {
				$key = (int) ( $svc['service_id'] ?? 0 );
				if ( $key && isset( $seen[ $key ] ) ) {
					continue;
				}
				if ( $key ) {
					$seen[ $key ] = true;
				}
				$services[] = $svc;
			}
		}
		return $services;
	}

	/**
	 * Get paginated appointments for an employee.
	 *
	 * @param int $employee_id Employee ID.
	 * @param int $page Current page number.
	 * @param int $per_page Items per page.
	 *
	 * @return array Paginated appointments data.
	 */
	public function getAppointments( $employee_id, $page = 1, $per_page = 10, $search = '', $status = '' ) {
		$offset      = ( $page - 1 ) * $per_page;
		$ids         = $this->getRelatedEmployeeIds( (int) $employee_id );
		$booking     = $this->employeeRepo->getPaginatedAppointments(
			$ids,
			$per_page,
			$offset,
			$search,
			$status
		);
		$total_items = $this->employeeRepo->appointmentCount( $ids, $status );

		$booking_list = array_map(
			function ( $item ) {
				return apply_filters( 'rtrb_my_booking_item_data', (object) $item );
			},
			is_array( $booking ) ? $booking : $booking->toArray()
		);

		return $this->paginate( $booking_list, $page, $per_page, $total_items );
	}

	/**
	 * Get paginated clients for an employee.
	 *
	 * @param int $employee_id Employee ID.
	 * @param int $page Current page number.
	 * @param int $per_page Items per page.
	 *
	 * @return array Paginated clients data.
	 */
	public function getClients( $employee_id, $page = 1, $per_page = 10 ) {
		$offset  = ( $page - 1 ) * $per_page;
		$ids     = $this->getRelatedEmployeeIds( (int) $employee_id );
		$clients = $this->employeeRepo->getPaginatedClients(
			$ids,
			$per_page,
			$offset
		);

		// Get total unique clients count.
		$total_items = $this->employeeRepo->getActiveClientCount( $ids );

		return $this->paginate( $clients, $page, $per_page, $total_items );
	}

	public function getPaymentData( $employee_id, $date_filter, $page = 1, $per_page = 10, $status = '', $search = '' ) {
		$offset        = ( $page - 1 ) * $per_page;
		$ids           = $this->getRelatedEmployeeIds( (int) $employee_id );
		$date_range    = $this->employeeRepo->getDateRangeForFilter( $date_filter );
		$payments_data = $this->employeeRepo->getPaginatedPayments( $ids, $date_range, $per_page, $offset, $status, $search );

		$payments     = ! empty( $payments_data['data'] ) ? $payments_data['data'] : [];
		$status_total = ! empty( $payments_data['count'] ) ? $payments_data['count'] : 0;
		$statistics   = $this->employeeRepo->getTotalPaymentCount( $ids, $date_range );
		$data         = array(
			'statistics' => $statistics,
			'payments'   => $payments
		);

		return $this->paginate( $data, $page, $per_page, $status_total );
	}

	public function getScheduleData( $employee_id, $params ) {
		$page     = $params['page'] ?? 1;
		$per_page = $params['per_page'] ?? 10;
		$search   = $params['search'] ?? '';
		$status   = $params['status'] ?? '';
		$ids      = $this->getRelatedEmployeeIds( (int) $employee_id );

		$appointments = $this->getAppointments( $employee_id, $page, $per_page, $search, $status );

		$total_pending   = $this->employeeRepo->getPendingAppointmentCount( $ids );
		$total_completed = $this->employeeRepo->getCompletedAppointmentCount( $ids );
		$total_cancelled = $this->employeeRepo->getCancelledAppointmentCount( $ids );
		$total_confirmed = $this->employeeRepo->getConfirmedAppointmentCount( $ids );
		$total_items     = $total_pending + $total_completed + $total_cancelled + $total_confirmed;

		return array(
			'appointments' => $appointments,
			'statistics'   => array(
				'pending'   => $total_pending,
				'completed' => $total_completed,
				'cancelled' => $total_cancelled,
				'confirmed' => $total_confirmed,
				'all'       => $total_items
			)
		);

	}

	public function updateAppointmentStatus( $appointment_id, $service, $status, $request ) {
		return $service->executeStatusChange( $service, $appointment_id, $status, $request );
	}

	public function getProfileData( $employee_id ) {
		$user_profile                    = (array) $this->userRepo->get_profile( $employee_id );
		$user_profile['image_full_path'] = $this->userRepo->getImageUrl( $user_profile['id'] );
		$user                            = (array) User::where( 'id', $employee_id )->first();

		return array_merge( $user_profile, $user );
	}

	public function updateProfileData( $request ) {
		$employee_id     = $request->get_param( 'employee_id' );
		$user            = $this->userRepo->find( $employee_id );
		$data            = $request->get_params();
		$data['user_id'] = $employee_id;
		$user->update( $request->get_params() );
		$user_profile = Container::resolve( UserProfileRepository::class );
		$user_profile->updateProfile( $employee_id, $data );

		return $this->getProfileData( $employee_id );
	}

	public function changePassword( $request ) {
		$employee_id      = $request->get_param( 'employee_id' );
		$current_password = $request->get_param( 'current_password' );
		$new_password     = $request->get_param( 'new_password' );

		$user_service = Container::resolve( UserService::class );
		$result       = $user_service->updatePassword( $employee_id, $current_password, $new_password );

		return $result;
	}

	/**
	 * Build a standardized paginated response array.
	 *
	 * @param array $data The data items for the current page.
	 * @param int $page The current page number.
	 * @param int $per_page The number of items per page.
	 * @param int $total_items The total number of items across all pages.
	 *
	 * @return array The formatted paginated response with data and pagination metadata.
	 */
	public function paginate( array $data, int $page, int $per_page, int $total_items ): array {
		$total_pages = $per_page > 0 ? (int) ceil( $total_items / $per_page ) : 0;

		return array(
			'data'       => $data,
			'pagination' => array(
				'current_page' => $page,
				'per_page'     => $per_page,
				'total_items'  => $total_items,
				'total_pages'  => $total_pages,
				'has_previous' => $page > 1,
				'has_next'     => $page < $total_pages,
			),
		);
	}
}