<?php
if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}


if ( ! class_exists( 'OsCustomersController' ) ) :


	class OsCustomersController extends OsController {

		function __construct() {
			parent::__construct();


			$this->views_folder          = LATEPOINT_VIEWS_ABSPATH . 'customers/';
			$this->vars['page_header']   = OsMenuHelper::get_menu_items_by_id( 'customers' );
			$this->vars['breadcrumbs'][] = array(
				'label' => __( 'Customers', 'latepoint' ),
				'link'  => OsRouterHelper::build_link( OsRouterHelper::build_route_name( 'customers', 'index' ) ),
			);
		}

		public function destroy() {
			if ( filter_var( $this->params['id'], FILTER_VALIDATE_INT ) ) {
				$this->check_nonce( 'destroy_customer_' . $this->params['id'] );
				$customer = new OsCustomerModel( $this->params['id'] );
				if ( $customer->delete() ) {
					$status        = LATEPOINT_STATUS_SUCCESS;
					$response_html = __( 'Customer Removed', 'latepoint' );
				} else {
					$status        = LATEPOINT_STATUS_ERROR;
					$response_html = __( 'Error Removing Customer', 'latepoint' );
				}
			} else {
				$status        = LATEPOINT_STATUS_ERROR;
				$response_html = __( 'Error Removing Customer', 'latepoint' );
			}

			if ( $this->get_return_format() == 'json' ) {
				$this->send_json(
					array(
						'status'  => $status,
						'message' => $response_html,
					) 
				);
			}
		}


		public function view_customer_log() {

			$activities = new OsActivityModel();
			$activities = $activities->where( [ 'customer_id' => absint( $this->params['customer_id'] ) ] )->order_by( 'id desc' )->get_results_as_models();

			$customer = new OsCustomerModel( $this->params['customer_id'] );

			$this->vars['customer']   = $customer;
			$this->vars['activities'] = $activities;

			$this->format_render( __FUNCTION__ );
		}


		public function quick_new() {
			$customer = new OsCustomerModel();

			$this->vars['customer'] = $customer;

			$this->format_render( 'quick_edit' );
		}

		public function quick_edit() {
			if ( ! filter_var( $this->params['customer_id'], FILTER_VALIDATE_INT ) ) {
				$this->access_not_allowed();
			}
			$customer = new OsCustomerModel( $this->params['customer_id'] );

			$this->vars['customer'] = $customer;

			$this->format_render( __FUNCTION__ );
		}


		public function inline_edit_form() {
			$selected_customer = new OsCustomerModel();
			if ( isset( $this->params['customer_id'] ) ) {
				$selected_customer->load_by_id( $this->params['customer_id'] );
			}
			$this->vars['default_fields_for_customer'] = OsSettingsHelper::get_default_fields_for_customer();
			$this->vars['selected_customer']           = $selected_customer;
			$this->format_render( __FUNCTION__ );
		}

		public function set_as_guest() {
			// CSRF protection
			$this->check_nonce( 'set_customer_as_guest_' . $this->params['id'] );

			if ( filter_var( $this->params['id'], FILTER_VALIDATE_INT ) ) {
				$customer = new OsCustomerModel( $this->params['id'] );
				if ( $customer->update_attributes( [ 'is_guest' => true ] ) ) {
					$status        = LATEPOINT_STATUS_SUCCESS;
					$response_html = __( 'Customer is now allowed to book without password', 'latepoint' );
				} else {
					$status        = LATEPOINT_STATUS_ERROR;
					$response_html = $customer->get_error_messages();
				}
			} else {
				$status        = LATEPOINT_STATUS_ERROR;
				$response_html = __( 'Error setting customer as guest', 'latepoint' );
			}

			if ( $this->get_return_format() == 'json' ) {
				$this->send_json(
					array(
						'status'  => $status,
						'message' => $response_html,
					) 
				);
			}
		}

		/*
		  Edit customer
		*/

		public function edit_form() {
			$this->vars['page_header']   = __( 'Edit Customer', 'latepoint' );
			$this->vars['breadcrumbs'][] = array(
				'label' => __( 'Edit Customer', 'latepoint' ),
				'link'  => false,
			);

			if ( filter_var( $this->params['id'], FILTER_VALIDATE_INT ) ) {
				// check if allowed to access
				$customer                          = new OsCustomerModel();
				$customer                          = $customer->where( [ LATEPOINT_TABLE_CUSTOMERS . '.id' => absint( $this->params['id'] ) ] )->filter_allowed_records()->set_limit( 1 )->get_results_as_models();
				$this->vars['customer']            = $customer;
				$this->vars['wp_users_for_select'] = OsWpUserHelper::get_wp_users_for_select();
			}

			$this->format_render( __FUNCTION__ );
		}


		public function query_for_booking_form() {
			$query                   = trim( $this->params['query'] );
			$sql_query               = '%' . $query . '%';
			$query                   = $this->params['query'];
			$customers               = new OsCustomerModel();
			$this->vars['query']     = $query;
			$this->vars['customers'] = $customers->where(
				array(
					'OR' => array(
						'CONCAT (first_name, " ", last_name) LIKE ' => $sql_query,
						'email LIKE' => $sql_query,
						'phone LIKE' => $sql_query,
					),
				) 
			)->set_limit( 20 )->order_by( 'first_name asc, last_name asc' )->get_results_as_models();

			$this->format_render( __FUNCTION__ );
		}


		/*
		  Create customer
		*/

		public function create() {
			$this->check_nonce( 'new_customer' );
			$customer = new OsCustomerModel();
			// Security fix: Prevent mass assignment of wordpress_user_id by non-admin users.
			// Use admin scope if user is authenticated as admin, otherwise restrict to public fields.
			$customer->set_data( $this->params['customer'], OsAuthHelper::is_admin_logged_in() ? LATEPOINT_PARAMS_SCOPE_ADMIN : LATEPOINT_PARAMS_SCOPE_PUBLIC );
			if ( $customer->save() ) {
				// translators: %s is the html of a customer edit link
				$response_html = sprintf( __( 'Customer Created ID: %s', 'latepoint' ), '<span class="os-notification-link" ' . OsCustomerHelper::quick_customer_btn_html( $customer->id ) . '>' . $customer->id . '</span>' );
				$status        = LATEPOINT_STATUS_SUCCESS;
				do_action( 'latepoint_customer_created', $customer );
			} else {
				$response_html = $customer->get_error_messages();
				$status        = LATEPOINT_STATUS_ERROR;
			}
			if ( $this->get_return_format() == 'json' ) {
				$this->send_json(
					array(
						'status'  => $status,
						'message' => $response_html,
					) 
				);
			}
		}


		/*
		  Update customer
		*/

		public function update() {
			if ( isset( $this->params['customer']['id'] ) && filter_var( $this->params['customer']['id'], FILTER_VALIDATE_INT ) ) {
				$this->check_nonce( 'edit_customer_' . $this->params['customer']['id'] );
				$customer = new OsCustomerModel( $this->params['customer']['id'] );
				if ( ! $customer || ! OsRolesHelper::can_user_make_action_on_model_record( $customer, 'edit' ) ) {
					$response_html = __( 'Access Restricted', 'latepoint' );
					$status        = LATEPOINT_STATUS_ERROR;
				} else {
					$old_customer_data = $customer->get_data_vars();
					// Security fix: Prevent mass assignment of wordpress_user_id by non-admin users.
					// Use admin scope if user is authenticated as admin, otherwise restrict to public fields.
					$customer->set_data( $this->params['customer'], OsAuthHelper::is_admin_logged_in() ? LATEPOINT_PARAMS_SCOPE_ADMIN : LATEPOINT_PARAMS_SCOPE_PUBLIC );
					if ( $customer->save() ) {
						// translators: %s is the html of a customer edit link
						$response_html = sprintf( __( 'Customer Updated ID: %s', 'latepoint' ), '<span class="os-notification-link" ' . OsCustomerHelper::quick_customer_btn_html( $customer->id ) . '>' . $customer->id . '</span>' );
						$status        = LATEPOINT_STATUS_SUCCESS;
						do_action( 'latepoint_customer_updated', $customer, $old_customer_data );
					} else {
						$response_html = $customer->get_error_messages();
						$status        = LATEPOINT_STATUS_ERROR;
					}
				}
			} else {
				$response_html = __( 'Invalid customer ID', 'latepoint' );
				$status        = LATEPOINT_STATUS_ERROR;
			}
			if ( $this->get_return_format() == 'json' ) {
				$this->send_json(
					array(
						'status'  => $status,
						'message' => $response_html,
					) 
				);
			}
		}

		public function mini_profile() {
			if ( filter_var( $this->params['customer_id'], FILTER_VALIDATE_INT ) ) {
				$customer                       = new OsCustomerModel( $this->params['customer_id'] );
				$this->vars['upcoming_booking'] = $customer->get_future_bookings( 1, true );
				$this->vars['customer']         = $customer;


				$pie_labels     = [];
				$pie_colors     = [];
				$pie_values     = [];
				$pie_chart_data = OsBookingHelper::get_stat(
					'bookings',
					[
						'group_by'    => 'status',
						'customer_id' => $customer->id,
					] 
				);
				$colors         = [ '#2752E4', '#C066F1', '#26B7DD', '#E8C634', '#19CED6', '#2FEAA3', '#252a3e', '#8d87a5', '#b9b784' ];
				$status_colors  = [
					LATEPOINT_BOOKING_STATUS_APPROVED  => '#35d893',
					LATEPOINT_BOOKING_STATUS_PENDING   => '#e6b935',
					LATEPOINT_BOOKING_STATUS_PAYMENT_PENDING => '#4ca4ef',
					LATEPOINT_BOOKING_STATUS_CANCELLED => '#f1585d',
				];
				$i              = 0;
				foreach ( $pie_chart_data as $pie_data ) {
					$pie_labels[] = $pie_data['status'];
					$pie_colors[] = isset( $status_colors[ $pie_data['status'] ] ) ? $status_colors[ $pie_data['status'] ] : $colors[ $i ];
					$pie_values[] = $pie_data['stat'];
					$i++;
				}

				$this->vars['pie_chart_data'] = [
					'labels' => $pie_labels,
					'colors' => $pie_colors,
					'values' => $pie_values,
				];


				$this->set_layout( 'none' );
				$response_html = $this->format_render_return( __FUNCTION__ );
			} else {
				$status        = LATEPOINT_STATUS_ERROR;
				$response_html = __( 'Error Accessing Customer', 'latepoint' );
			}

			if ( $this->get_return_format() == 'json' ) {
				$this->send_json(
					array(
						'status'  => $status,
						'message' => $response_html,
					) 
				);
			}
		}

		public function connect_all_to_wp_users() {
			// CSRF protection
			$this->check_nonce( 'connect_all_customers_to_wp_users' );

			$customers = new OsCustomerModel();
			$customers = $customers->where( [ 'wordpress_user_id' => [ 'OR' => [ 0, 'IS NULL' ] ] ] )->get_results_as_models();
			if ( $customers ) {
				foreach ( $customers as $customer ) {
					$wp_user_id = OsCustomerHelper::create_wp_user_for_customer( $customer );
					if ( $wp_user_id ) {
						//check if wp user already connected to another customer
						$connected_customer = new OsCustomerModel();
						$connected_customer = $connected_customer->where( [ 'wordpress_user_id' => $wp_user_id ] )->set_limit( 1 )->get_results_as_models();
						if ( ! $connected_customer ) {
							$customer->update_attributes( [ 'wordpress_user_id' => $wp_user_id ] );
						}
					}
				}
			}

			if ( $this->get_return_format() == 'json' ) {
				$this->send_json(
					array(
						'status'  => LATEPOINT_STATUS_SUCCESS,
						'message' => __( 'Customers Connected', 'latepoint' ),
					) 
				);
			}
		}

		public function disconnect_from_wp_user() {
			// CSRF protection
			$this->check_nonce( 'disconnect_customer_from_wp_user_' . $this->params['customer_id'] );

			$customer_id = $this->params['customer_id'];
			$customer    = new OsCustomerModel();
			$customer    = $customer->where( [ 'id' => $customer_id ] )->set_limit( 1 )->get_results_as_models();
			if ( $customer ) {
				$customer->update_attributes( [ 'wordpress_user_id' => null ] );
			}
			if ( $this->get_return_format() == 'json' ) {
				$this->send_json(
					array(
						'status'  => LATEPOINT_STATUS_SUCCESS,
						'message' => __( 'Customer Disconnected', 'latepoint' ),
					) 
				);
			}
		}

		public function connect_to_wp_user() {
			// CSRF protection
			$this->check_nonce( 'connect_customer_to_wp_user_' . $this->params['customer_id'] );

			$customer_id = $this->params['customer_id'];
			$customer    = new OsCustomerModel();
			$customer    = $customer->where( [ 'id' => $customer_id ] )->set_limit( 1 )->get_results_as_models();
			if ( $customer && ! $customer->wordpress_user_id ) {
				$wp_user = OsCustomerHelper::create_wp_user_for_customer( $customer );
			}
			if ( $this->get_return_format() == 'json' ) {
				$this->send_json(
					array(
						'status'  => LATEPOINT_STATUS_SUCCESS,
						'message' => __( 'Customer Connected', 'latepoint' ),
					) 
				);
			}
		}


		public function index() {
			$this->vars['page_header'] = false;
			$page_number               = isset( $this->params['page_number'] ) ? $this->params['page_number'] : 1;
			$per_page                  = OsSettingsHelper::get_number_of_records_per_page();
			$offset                    = ( $page_number > 1 ) ? ( ( $page_number - 1 ) * $per_page ) : 0;


			$customers  = new OsCustomerModel();
			$query_args = [];

			$filter = isset( $this->params['filter'] ) ? $this->params['filter'] : false;

			// TABLE SEARCH FILTERS
			if ( $filter ) {
				if ( $filter['id'] ) {
					$query_args['id'] = $filter['id'];
				}
				if ( $filter['registration_date_from'] && $filter['registration_date_to'] ) {
					$query_args[ LATEPOINT_TABLE_CUSTOMERS . '.created_at >=' ] = $filter['registration_date_from'];
					$query_args[ LATEPOINT_TABLE_CUSTOMERS . '.created_at <=' ] = $filter['registration_date_to'];
				}
				if ( $filter['customer'] ) {
					$query_args[ 'concat_ws(" ", ' . LATEPOINT_TABLE_CUSTOMERS . '.first_name,' . LATEPOINT_TABLE_CUSTOMERS . '.last_name) LIKE' ] = '%' . $filter['customer'] . '%';
					$this->vars['customer_name_query'] = $filter['customer'];
				}
				if ( $filter['phone'] ) {
					$query_args['phone LIKE']  = '%' . $filter['phone'] . '%';
					$this->vars['phone_query'] = $filter['phone'];
				}
				if ( $filter['email'] ) {
					$query_args['email LIKE']  = '%' . $filter['email'] . '%';
					$this->vars['email_query'] = $filter['email'];
				}
			}


			// OUTPUT CSV IF REQUESTED
			if ( isset( $this->params['download'] ) && $this->params['download'] == 'csv' ) {
				// CSRF protection
				$this->check_nonce( 'customers_csv_export' );

				$csv_filename = 'customers_' . OsUtilHelper::random_text();

				header( 'Content-Type: text/csv' );
				header( "Content-Disposition: attachment; filename={$csv_filename}.csv" );

				$labels_row = [
					__( 'ID', 'latepoint' ),
					__( 'Name', 'latepoint' ),
					__( 'Phone', 'latepoint' ),
					__( 'Email', 'latepoint' ),
					__( 'Total Appointments', 'latepoint' ),
					__( 'Next Appointment', 'latepoint' ),
					__( 'Registered On', 'latepoint' ),
				];


				$customers_data   = [];
				$customers_data[] = $labels_row;


				$customers_arr = $customers->where( $query_args )->filter_allowed_records()->order_by( 'id desc' )->get_results_as_models();
				if ( $customers_arr ) {
					foreach ( $customers_arr as $customer ) {
						$next_booking     = $customer->get_future_bookings( 1, true );
						$values_row       = [
							$customer->id,
							$customer->full_name,
							$customer->phone,
							$customer->email,
							$customer->total_bookings_count,
							$next_booking ? $next_booking->nice_start_datetime : 'n/a',
							$customer->formatted_created_date(),
						];
						$values_row       = apply_filters( 'latepoint_customer_row_for_csv_export', $values_row, $customer, $this->params );
						$customers_data[] = $values_row;
					}
				}
				$customers_data = apply_filters( 'latepoint_customers_data_for_csv_export', $customers_data, $this->params );
				OsCSVHelper::array_to_csv( $customers_data );

				return;
			}

			$customers->where( $query_args )->filter_allowed_records();
			$count_total_customers = clone $customers;

			$total_customers = $count_total_customers->count();
			$total_pages     = ceil( $total_customers / $per_page );


			$this->vars['customers_violating_auth_rules'] = OsAuthHelper::count_total_customers_violating_auth_rules();

			$this->vars['customers']       = $customers->set_limit( $per_page )->set_offset( $offset )->order_by( 'id desc' )->get_results_as_models();
			$this->vars['total_customers'] = $total_customers;

			$this->vars['total_pages']         = ceil( $total_customers / $per_page );
			$this->vars['per_page']            = $per_page;
			$this->vars['current_page_number'] = $page_number;

			$this->vars['showing_from'] = ( ( $page_number - 1 ) * $per_page ) ? ( ( $page_number - 1 ) * $per_page ) : 1;
			$this->vars['showing_to']   = min( $page_number * $per_page, $this->vars['total_customers'] );

			$this->format_render(
				[
					'json_view_name' => '_table_body',
					'html_view_name' => __FUNCTION__,
				],
				[],
				[
					'total_pages'   => $total_pages,
					'showing_from'  => $this->vars['showing_from'],
					'showing_to'    => $this->vars['showing_to'],
					'total_records' => $total_customers,
				] 
			);
		}


		public function import_csv_modal() {
			$current_step               = $this->params['step'] ?? 'upload_csv';
			$steps                      = [
				'upload_csv' => [ 'next_step' => 'mapping' ],
				'mapping'    => [ 'next_step' => 'importing' ],
			];
			$this->vars['current_step'] = $current_step;
			$this->vars['next_step']    = array_key_exists( $current_step, $steps ) ? $steps[ $current_step ]['next_step'] : 'upload_csv';
			$this->format_render( __FUNCTION__ );
		}

		public function import_load_step() {
			$this->check_nonce( 'import_customers_csv' );
			$current_step = $this->params['step'] ?? 'upload_csv';
			$status       = LATEPOINT_STATUS_SUCCESS;

			try {
				switch ( $current_step ) {
					case 'upload_csv':
						$response_html = $this->_handle_upload_step();
						break;

					case 'mapping':
						$response_html = $this->_handle_mapping_step();
						break;

					case 'confirmation':
						$response_html = $this->_handleConfirmationStep();
						break;

					default:
						throw new Exception( 'Invalid step provided' );
				}
			} catch ( Exception $e ) {
				$response_html = $e->getMessage();
				$status        = LATEPOINT_STATUS_ERROR;
			}

			$this->send_json(
				array(
					'status'  => $status,
					'message' => $response_html,
				) 
			);
		}

		private function _handle_upload_step(): string {
			$file_path = OsCSVHelper::upload_csv_file( $this->files, 'latepoint_customers_csv' );
			$csv_data  = OsCSVHelper::get_csv_data( $file_path, 1 );

			return $this->render(
				$this->views_folder . 'import_steps/step_mapping.php',
				'none',
				[
					'csv_data' => $csv_data,
				] 
			);
		}

		private function _handle_mapping_step(): string {
			$columnMapping = $this->params['latepoint_column_mapping'] ?? [];

			if ( ! OsCustomerImportHelper::validate_import_mapping( $columnMapping ) ) {
				throw new Exception( esc_html__( 'Email field is required', 'latepoint' ) );
			}

			$csv_data          = OsCSVHelper::get_csv_data( OsCustomerImportHelper::get_import_tmp_filepath() );
			$validation_result = OsCustomerImportHelper::validate_csv_data( $csv_data, $columnMapping );

			return $this->render(
				$this->views_folder . 'import_steps/step_confirmation.php',
				'none',
				[
					'conflicts'                => $validation_result['conflicts'],
					'can_be_imported'          => $validation_result['importable_count'],
					'latepoint_column_mapping' => $columnMapping,
				] 
			);
		}


		private function _handleConfirmationStep(): string {
			$update_existing_customers = ! empty( $this->params['latepoint_update_customers_acknowledgement'] ) && OsUtilHelper::is_on( $this->params['latepoint_update_customers_acknowledgement'] );
			$column_mapping            = ! empty( $this->params['latepoint_column_mapping'] ) ? json_decode( $this->params['latepoint_column_mapping'], true ) : [];

			$file_path = OsCustomerImportHelper::get_import_tmp_filepath();
			$csv_data  = OsCSVHelper::get_csv_data( $file_path );

			$importResult = OsCustomerImportHelper::import_customers( $csv_data, $column_mapping, $update_existing_customers );

			// Cleanup after successful import
			OsCustomerImportHelper::cleanup_stored_file();

			return $this->render(
				$this->views_folder . 'import_steps/step_done.php',
				'none',
				[
					'skipped_records' => $importResult['skipped_count'],
					'updated_records' => $importResult['updated_count'],
				] 
			);
		}
	}


endif;
