<?php
/**
 * Defines Contacts page functionality
 *
 * @link       https://personalizewp.com/
 * @since      3.2.0 Merged into PWP
 * @since      1.0.0
 *
 * @package    PersonalizeWP
 * @subpackage PersonalizeWP/Admin
 */

namespace PersonalizeWP\Admin;

use PersonalizeWP\Admin\Admin;
use PersonalizeWP\Admin\Admin_Base_Page;
use PersonalizeWP\Model\Contact;
use PersonalizeWP\Model\Activity;
use PersonalizeWP\Model\Segment;
use PersonalizeWP\Integrations\WooCommerce\WooCommerce_Memberships_Teams;

defined( 'ABSPATH' ) || exit; // Exit if accessed directly.

/**
 * Defines Contacts page functionality
 */
class PageContacts extends Admin_Base_Page {

	/**
	 * Slug for contacts admin page
	 */
	const SLUG = 'personalizewp/profiles';

	/**
	 * URL for main contacts admin page (listing)
	 *
	 * @var string
	 */
	public static $index_url = 'admin.php?page=' . self::SLUG;

	/**
	 * URL for view contact page
	 *
	 * @var string
	 */
	public static $view_url = 'admin.php?page=' . self::SLUG . '&' . Admin::URL_ACTION . '=view&id=';

	/**
	 * URL for view team page.
	 *
	 * @var string
	 */
	public static $view_team_url = 'admin.php?page=' . self::SLUG . '&' . Admin::URL_ACTION . '=view-team&team_id=';

	/**
	 * URL for deleting a contact
	 *
	 * @var string
	 */
	public static $delete_url = 'admin.php?page=' . self::SLUG . '&' . Admin::URL_ACTION . '=delete&id=';

	/**
	 * URL for removing a contact segment
	 *
	 * @var string
	 */
	public static $remove_contact_segment = 'admin.php?page=' . self::SLUG . '&' . Admin::URL_ACTION . '=remove-segment&id=';

	/**
	 * Store the path for Contacts templates
	 *
	 * @var string
	 */
	public $template_path;

	/**
	 * Constructor
	 */
	protected function __construct() {
		parent::__construct();

		$this->page_title    = __( 'Visitor Profiles', 'personalizewp' );
		$this->template_path = plugin_dir_path( __DIR__ ) . 'admin/partials/contacts/';

		add_action( 'admin_init', [ $this, 'process' ] );
		add_filter( 'set-screen-option', [ $this, 'set_screen_options' ], 10, 3 );
		add_filter( 'parent_file', [ $this, 'switch_active_menu_item' ] );

		add_filter( 'personalizewp_activity_delete_redirect', [ $this, 'filter_activity_delete_redirect' ], 10, 3 );
		add_filter( 'personalizewp_activity_row_actions', [ $this, 'filter_activity_row_actions' ], 10, 2 );
		add_filter( 'personalizewp_activity_sortable_columns', [ $this, 'filter_activity_sortable_columns' ] );
		add_filter( 'personalizewp_activity_table_columns', [ $this, 'filter_activity_columns' ] );
	}

	/**
	 * Display the Dashboard screen options.
	 */
	public function dashboard_screen_options() {
		$screen = get_current_screen();

		$is_screen = is_object( $screen ) && str_ends_with( $screen->id, self::SLUG );
		if ( ! $is_screen ) {
			return;
		}
		// Re-trigger core WP, as admins' call runs way too early IMHO.
		set_screen_options();

		if ( in_array( $this->current_action, array( 'view', 'view-team' ), true ) ) {
			$args = array(
				'label'   => __( 'Number of Recent Events per page (max 200):', 'personalizewp' ),
				'default' => 20,
				'option'  => 'edit_pwp_recent_events_per_page',
			);
		} else {
			// Default to Visitor Profiles
			$args = array(
				'label'   => __( 'Number of Visitor Profiles per page (max 200):', 'personalizewp' ),
				'default' => 20,
				'option'  => 'edit_pwp_contacts_per_page',
			);
		}
		add_screen_option( 'per_page', $args );
	}

	/**
	 * Store the screen options.
	 *
	 * @param mixed  $screen_option The value to save instead of the option value.
	 *                              Default false (to skip saving the current option).
	 * @param string $option        The option name.
	 * @param int    $value         The option value.
	 */
	public function set_screen_options( $screen_option, $option, $value ) {
		if ( in_array( $option, array( 'edit_pwp_contacts_per_page', 'edit_pwp_recent_events_per_page' ), true ) ) {
			// Enforce maximum of 200.
			return min( max( (int) $value, 1 ), 200 );
		}
		return $screen_option;
	}

	/**
	 * Modifies admin menu of PersonalizeWP
	 * Sets active page for sub-sections which are invisible in the menu.
	 *
	 * @since 3.3.0
	 *
	 * @param string $parent_file The parent file.
	 *
	 * @return string
	 */
	public function switch_active_menu_item( $parent_file ) {
		global $plugin_page;

		if ( self::SLUG === $plugin_page ) {
			// Pretend to be on Recent Events, for highlighted menu item.
			$plugin_page = PageActivities::SLUG;
		}

		return $parent_file;
	}

	/**
	 * Process the current Contact request, typically POST/GET, followed by a redirect.
	 *
	 * @return void
	 */
	public function process() {
		// Double check for user caps before any possible processing of data.
		if ( ! current_user_can( Admin::CAP ) ) {
			return;
		}

		if ( self::SLUG !== $this->current_page ) {
			return;
		}

		$item_id    = (int) isset( $_REQUEST['id'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['id'] ) ) : false;
		$contact_id = (int) isset( $_REQUEST['contact_id'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['contact_id'] ) ) : false;

		switch ( $this->current_action ) {
			case 'delete':
				if ( empty( $item_id ) ) {
					wp_safe_redirect( admin_url( self::$index_url ) );
					exit;
				}
				check_admin_referer( 'delete-contact-' . $item_id ); // Immediately dies on failing.
				$this->delete_action( $item_id );
				break;

			case 'remove-segment':
				if ( empty( $item_id ) || empty( $contact_id ) ) {
					wp_safe_redirect( admin_url( self::$index_url ) );
					exit;
				}
				check_admin_referer( 'remove-segment-' . $item_id . '-' . $contact_id ); // Immediately dies on failing.

				$this->remove_segment_action( $item_id, $contact_id );
				break;
		}
	}

	/**
	 * Route to the correct screen
	 *
	 * @return void
	 */
	public function route() {
		// Double check for user caps before any possible processing of data.
		if ( ! current_user_can( Admin::CAP ) ) {
			return;
		}

		if ( self::SLUG !== $this->current_page ) {
			return;
		}

		$contact_id = (int) isset( $_REQUEST['id'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['id'] ) ) : false; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reason: used as intval
		$team_id    = (int) isset( $_REQUEST['team_id'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['team_id'] ) ) : false; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reason: used as intval

		switch ( $this->current_action ) {
			case 'view':
				if ( empty( $contact_id ) ) {
					wp_safe_redirect( admin_url( self::$index_url ) );
					die();
				}

				$this->view_screen( $contact_id );
				break;

			case 'view-team':
				if ( empty( $team_id ) ) {
					wp_safe_redirect( admin_url( self::$index_url ) );
					die();
				}

				$this->view_team_screen( $team_id );
				break;

			case 'index':
			default:
				$this->index_screen();
				break;
		}
	}

	/**
	 * Displays Contacts listing screen
	 *
	 * @return void
	 */
	protected function index_screen() {

		$status_message = '';
		// Trigger messaging from actions.
		if ( isset( $_REQUEST['deleted'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- this is only displaying a message with no dynamic values.
			$status_message = __( 'Visitor Profile deleted', 'personalizewp' );
		}
		if ( $status_message ) {
			wp_admin_notice(
				'<span class="dashicons dashicons-yes-alt"></span>' . $status_message,
				array(
					'type'        => 'success',
					'id'          => 'message',
					'dismissible' => true,
				)
			);
		}

		$this->display_header();
		require_once $this->template_path . 'index.php';
		$this->display_footer();
	}

	/**
	 * View singular Contact screen
	 *
	 * @param int $contact_id Contact ID
	 *
	 * @return void
	 */
	protected function view_screen( $contact_id ) {

		$contact = Contact::get_instance( $contact_id );

		if ( ! $contact ) {
			$this->showError( __( 'You attempted to edit an item that does not exist. Perhaps it was deleted?', 'personalizewp' ) );
		}

		$status_message = '';
		// Trigger messaging from actions.
		if ( isset( $_REQUEST['deleted'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- this is only displaying a message with no dynamic values.
			$status_message = __( 'Visitor Profile activity deleted', 'personalizewp' );
		} elseif ( isset( $_REQUEST['removed_segment'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- this is only displaying a message with no dynamic values.
			$status_message = __( 'Visitor Segment removed', 'personalizewp' );
		}
		if ( $status_message ) {
			wp_admin_notice(
				'<span class="dashicons dashicons-yes-alt"></span>' . $status_message,
				array(
					'type'        => 'success',
					'id'          => 'message',
					'dismissible' => true,
				)
			);
		}

		// Add filter to restrict Activities to this specific Contact.
		add_filter( 'personalizewp_activity_request_clauses', [ $this, 'filter_activity_clauses' ], 10, 1 );
		add_filter( 'personalizewp_activity_filter_fields', [ $this, 'add_id_to_filter_activity_fields' ], 10 );

		$this->display_header();
		require_once $this->template_path . 'view.php';
		$this->display_footer();
	}

	/**
	 * View Team screen.
	 *
	 * @since 3.4.0
	 *
	 * @param int $team_id Team ID.
	 * @return void
	 */
	protected function view_team_screen( $team_id ) {

		// Double check Teams in use.
		if ( ! WooCommerce_Memberships_Teams::is_active() ) {
			wp_safe_redirect( admin_url( self::$index_url ) );
			die();
		}

		// Team variable used within template partial.
		$team = WooCommerce_Memberships_Teams::instance()->get_team_by_id( $team_id );
		if ( empty( $team ) ) {
			$this->showError( __( 'You attempted to view a team that does not exist. Perhaps it was deleted?', 'personalizewp' ) );
		}

		// Add filter to restrict Activities to this specific Team.
		add_filter( 'personalizewp_activity_filter_fields', [ $this, 'add_id_to_filter_activity_fields' ], 10 );

		$this->display_header();
		require_once $this->template_path . 'view-team.php';
		$this->display_footer();
	}

	/**
	 * Delete Contact
	 *
	 * @param int $contact_id Contact ID
	 *
	 * @return void
	 */
	protected function delete_action( $contact_id ) {

		$result = Contact::delete( $contact_id );
		if ( ! $result ) {
			// Nothing to do
			wp_safe_redirect( admin_url( self::$index_url ) );
			exit;
		}

		wp_safe_redirect( add_query_arg( array( 'deleted' => 1 ), admin_url( self::$index_url ) ) );
		exit;
	}

	/**
	 * Remove Segment entry from a Contact
	 *
	 * @param int $segment_id Segment ID
	 * @param int $contact_id Contact ID
	 *
	 * @return void
	 */
	protected function remove_segment_action( int $segment_id, int $contact_id ) {

		$segment = Segment::find( $segment_id );
		if ( ! $segment ) {
			// Nothing to do
			wp_safe_redirect( admin_url( self::$index_url ) );
			exit;
		}

		Segment::remove_contact( $segment_id, $contact_id );

		wp_safe_redirect( add_query_arg( array( 'removed_segment' => 1 ), admin_url( self::$view_url . $contact_id ) ) );
		die();
	}

	/**
	 * Filters the clauses used to select Activities for a specific Contact
	 *
	 * @since 3.3.0
	 *
	 * @param string[] $clauses Associative array of the clauses for the query.
	 *
	 * @return string[]
	 */
	public function filter_activity_clauses( $clauses ): array {
		global $wpdb;

		// Only restrict when viewing a specific contact profile
		$contact_id = isset( $_REQUEST['id'] ) ? (int) $_REQUEST['id'] : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reason: used as intval

		if ( self::SLUG === $this->current_page && $contact_id > 0 ) {
			$clauses['where'] .= $wpdb->prepare( ' AND contact_id = %d', $contact_id );
		}

		return $clauses;
	}

	/**
	 * Adds a hidden ID field when displaying the filter Events fields, only when on a singular Contact or Team view screen.
	 *
	 * @since 3.3.0
	 */
	public function add_id_to_filter_activity_fields() {

		$id_fields = array( 'id', 'team_id' );
		foreach ( $id_fields as $field ) {
			$item_id = isset( $_REQUEST[ $field ] ) ? (int) $_REQUEST[ $field ] : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Reason: used as intval
			if ( empty( $item_id ) ) {
				continue;
			}
			?>
				<input type="hidden" name="<?php echo esc_attr( $field ); ?>" value="<?php echo esc_attr( $item_id ); ?>" />
			<?php
		}
	}

	/**
	 * Filter activity row actions to add contact context to delete links.
	 *
	 * @since 3.3.0
	 *
	 * @param array $actions Row actions.
	 * @param array $item    Activity item data.
	 *
	 * @return array Modified row actions.
	 */
	public function filter_activity_row_actions( $actions, $item ): array {

		// Only apply when viewing a contact profile
		if ( 'view' !== $this->current_action || self::SLUG !== $this->current_page ) {
			return $actions;
		}

		// Overwrites the delete action to add contact context, if it exists.
		if ( isset( $actions['delete'] ) && ! empty( $item['contact_id'] ) ) {
			// Reconstruct delete URL with contact context instead of parsing HTML
			$type_label = PageActivities::translate_activity_type( $item['activity_type'] );
			$delete_url = PageActivities::$delete_activity_url . $item['ID'];
			$delete_url = add_query_arg( 'redirect_to_contact', $item['contact_id'], $delete_url );

			$actions['delete'] = sprintf(
				'<a class="trash" data-show-modal="#deleteActivityModal" href="%s" aria-label="%s">%s</a>',
				wp_nonce_url( admin_url( $delete_url ), 'delete-activity-' . $item['ID'] ),
				/* translators: %s: Activity name. */
				esc_attr( sprintf( _x( 'Delete &#8220;%s&#8221; activity', 'Activity name', 'personalizewp' ), $type_label ) ),
				esc_html__( 'Delete', 'personalizewp' )
			);
		}

		return $actions;
	}

	/**
	 * Filter activity delete redirect to go back to contact view.
	 *
	 * @since 3.3.0
	 *
	 * @param string $redirect_url Default redirect URL.
	 * @param int    $activity_id  The deleted activity ID.
	 * @param int    $contact_id   The contact ID associated with the activity.
	 *
	 * @return string Modified redirect URL.
	 */
	public function filter_activity_delete_redirect( $redirect_url, $activity_id, $contact_id ): string {

		// Check if we should redirect back to the contact view
		$redirect_to_contact = isset( $_REQUEST['redirect_to_contact'] ) ? (int) $_REQUEST['redirect_to_contact'] : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended

		// Cast contact_id to integer for proper comparison
		$contact_id = (int) $contact_id;

		if ( $redirect_to_contact && $redirect_to_contact === $contact_id ) {
			// Construct contact view URL properly
			$redirect_url = add_query_arg(
				array(
					'page'            => self::SLUG,
					Admin::URL_ACTION => 'view',
					'id'              => $contact_id,
					'deleted'         => 1,
				),
				admin_url( 'admin.php' )
			);
		}

		return $redirect_url;
	}

	/**
	 * Filter activity table columns for singular visitor profile view.
	 *
	 * @since 3.3.0
	 *
	 * @param array $columns Base activity columns.
	 *
	 * @return array Modified columns for visitor profile view.
	 */
	public function filter_activity_columns( array $columns ): array {

		// Only apply when viewing a singular contact profile
		if ( self::SLUG === $this->current_page && 'view' === $this->current_action ) {
			// Only ever showing our own activity entries
			unset( $columns['user_name'] );
		}

		return $columns;
	}

	/**
	 * Filter activity sortable columns to add sorting for contact profile activities.
	 *
	 * @since 3.3.0
	 *
	 * @param array $sortable Sortable columns array.
	 *
	 * @return array Modified sortable columns.
	 */
	public function filter_activity_sortable_columns( array $sortable ): array {

		// Only apply when viewing a contact profile
		if ( 'view' !== $this->current_action || self::SLUG !== $this->current_page ) {
			return $sortable;
		}

		// Add sortable columns for contact profile activities.
		return array(
			'activity_type' => 'activity_type',
			'object_id'     => 'object_id',
			'created'       => array( 'created', true, __( 'Created', 'personalizewp' ), __( 'Table ordered by Created date.', 'personalizewp' ), 'desc' ),
			'lead_score'    => array( 'lead_score', false ),
		);
	}
}
