<?php

namespace KaizenCoders\MagicLink\Admin;

use KaizenCoders\MagicLink\Helper;

class Magic_Links_Table extends US_List_Table {

	/**
	 * @since 1.2.1
	 * @var string
	 */
	public static $option_per_page = 'magic_links_per_page';

	/**
	 * Magic_Links_Table constructor.
	 */
	public function __construct() {
		parent::__construct( [
			'singular' => __( 'Magic Link', 'magic-link' ),
			'plural'   => __( 'Magic Links', 'magic-link' ),
			'ajax'     => false,
			'screen'   => 'magic_links',
		] );
	}

	/**
	 * Add Screen Option
	 *
	 * @since 1.2.1
	 */
	public static function screen_options() {
		$action = Helper::get_request_data( 'action' );

		if ( 'new' === $action ) {
			return;
		}

		$option = 'per_page';
		$args   = [
			'label'   => __( 'Number of Magic Links per page', 'magic-link' ),
			'default' => 10,
			'option'  => self::$option_per_page,
		];

		add_screen_option( $option, $args );
	}

	/**
	 * Render magic links page
	 *
	 * @since 1.2.1
	 */
	public function render() {
		$action = Helper::get_request_data( 'action' );

		if ( 'new' === $action ) {
			$this->render_form();

			return;
		}

		$template_data = [
			'object' => $this,
			'title'  => __( 'Magic Links', 'magic-link' ),
		];

		ob_start();

		include KC_ML_ADMIN_TEMPLATES_DIR . '/magic-links.php';
	}

	/**
	 * Render the Add New magic link form.
	 *
	 * @since 1.2.1
	 */
	public function render_form() {
		$submitted = Helper::get_request_data( 'submitted' );

		$template_data = [
			'title'        => __( 'Create Magic Link', 'magic-link' ),
			'button_text'  => __( 'Create Magic Link', 'magic-link' ),
			'form_action'  => admin_url( 'admin.php?page=magic-link-links&action=new' ),
			'form_data'    => $this->get_form_data(),
			'message'      => '',
			'message_type' => '',
		];

		if ( 'submitted' === $submitted ) {
			$nonce = Helper::get_request_data( '_wpnonce' );

			if ( ! wp_verify_nonce( $nonce, 'kc_ml_add_magic_link' ) ) {
				$template_data['message']      = __( 'Security check failed. Please try again.', 'magic-link' );
				$template_data['message_type'] = 'error';
			} else {
				$form_data = Helper::get_post_data( 'form_data', [], false );

				$validation = $this->validate_data( $form_data );

				if ( 'error' === $validation['status'] ) {
					$template_data['message']      = $validation['message'];
					$template_data['message_type'] = 'error';
					$template_data['form_data']    = $form_data;
				} else {
					$result = $this->save_magic_link( $form_data );

					$redirect_url = add_query_arg( [
						'page'       => 'magic-link-links',
						'message'    => 'created',
						'created_id' => $result['created_id'],
					], admin_url( 'admin.php' ) );

					if ( $result['send_email'] ) {
						$redirect_url = add_query_arg( 'email_sent', $result['email_sent'], $redirect_url );
					}

					wp_safe_redirect( $redirect_url );
					exit;
				}
			}
		}

		include KC_ML_ADMIN_TEMPLATES_DIR . '/magic-link-form.php';
	}

	/**
	 * Get default form data from global settings.
	 *
	 * @return array
	 *
	 * @since 1.2.1
	 */
	public function get_form_data() {
		$settings = KC_ML()->get_settings();

		return [
			'user_id'            => 0,
			'token_lifespan'     => Helper::get_data( $settings, 'general|settings|token_lifespan', 5 ),
			'token_lifespan_unit' => Helper::get_data( $settings, 'general|settings|token_lifespan_unit', 'minutes' ),
			'login_redirect'     => Helper::get_data( $settings, 'general|settings|login_redirect', home_url() ),
		];
	}

	/**
	 * Validate form data.
	 *
	 * @param array $form_data
	 *
	 * @return array
	 *
	 * @since 1.2.1
	 */
	public function validate_data( $form_data ) {
		$user_id        = absint( Helper::get_data( $form_data, 'user_id', 0 ) );
		$token_lifespan = absint( Helper::get_data( $form_data, 'token_lifespan', 0 ) );

		if ( empty( $user_id ) ) {
			return [
				'status'  => 'error',
				'message' => __( 'Please select a user.', 'magic-link' ),
			];
		}

		$user = get_user_by( 'id', $user_id );
		if ( ! $user ) {
			return [
				'status'  => 'error',
				'message' => __( 'Selected user does not exist.', 'magic-link' ),
			];
		}

		if ( $token_lifespan <= 0 ) {
			return [
				'status'  => 'error',
				'message' => __( 'Token lifespan must be greater than 0.', 'magic-link' ),
			];
		}

		return [
			'status'  => 'success',
			'message' => '',
		];
	}

	/**
	 * Save a new magic link to the database.
	 *
	 * @param array $form_data
	 *
	 * @return void
	 *
	 * @since 1.2.1
	 */
	public function save_magic_link( $form_data ) {
		global $wpdb;

		$user_id            = absint( Helper::get_data( $form_data, 'user_id', 0 ) );
		$token_lifespan     = absint( Helper::get_data( $form_data, 'token_lifespan', 5 ) );
		$token_lifespan_unit = sanitize_text_field( Helper::get_data( $form_data, 'token_lifespan_unit', 'minutes' ) );
		$send_email         = ! empty( Helper::get_data( $form_data, 'send_email', 0 ) );

		$token = Helper::generate_token();

		$multiplier = 60; // minutes
		if ( 'hours' === $token_lifespan_unit ) {
			$multiplier = 3600;
		} elseif ( 'days' === $token_lifespan_unit ) {
			$multiplier = 86400;
		}

		$expires = gmdate( 'Y-m-d H:i:s', time() + ( $token_lifespan * $multiplier ) );

		$wpdb->insert(
			$wpdb->prefix . 'kc_ml_magic_links',
			[
				'user_id'    => $user_id,
				'token'      => $token,
				'expires'    => $expires,
				'used'       => 0,
				'ip_address' => '',
				'created_at' => gmdate( 'Y-m-d H:i:s' ),
			],
			[ '%d', '%s', '%s', '%d', '%s', '%s' ]
		);

		$created_id = $wpdb->insert_id;
		$email_sent = 0;

		if ( $send_email ) {
			$user = get_user_by( 'id', $user_id );

			$magic_link_url = add_query_arg( [
				'magic_link'  => '1',
				'magic_token' => $token,
			], home_url() );

			$email_sent = Helper::send_magic_link_email( $user, $magic_link_url ) ? 1 : 0;
		}

		return [
			'created_id' => $created_id,
			'email_sent' => $email_sent,
			'send_email' => $send_email,
		];
	}

	/**
	 * Associative array of columns
	 *
	 * @return array
	 */
	public function get_columns() {
		return [
			'cb'         => '<input type="checkbox" />',
			//'id'         => __( 'ID', 'magic-link' ),
			'user'       => __( 'User', 'magic-link' ),
			'token'      => __( 'Token', 'magic-link' ),
			'status'     => __( 'Status', 'magic-link' ),
			'ip_address' => __( 'IP Address', 'magic-link' ),
			'created_at' => __( 'Created At', 'magic-link' ),
			'expires'    => __( 'Expires', 'magic-link' ),
		];
	}

	/**
	 * Columns to make sortable.
	 *
	 * @return array
	 */
	public function get_sortable_columns() {
		return [
			'id'         => [ 'id', true ],
			'created_at' => [ 'created_at', true ],
			'expires'    => [ 'expires', false ],
		];
	}

	/**
	 * Render the bulk edit checkbox
	 *
	 * @param array $item
	 *
	 * @return string
	 */
	public function column_cb( $item ) {
		return sprintf(
			'<input type="checkbox" name="magic_link_ids[]" value="%s"/>', $item['id']
		);
	}

	/**
	 * Default column rendering.
	 *
	 * @param array  $item
	 * @param string $column_name
	 *
	 * @return string
	 */
	public function column_default( $item, $column_name ) {
		switch ( $column_name ) {
			case 'created_at':
				return Helper::format_date_time( $item[ $column_name ] );
			case 'expires':
				return Helper::format_date_time( $item[ $column_name ] );
			default:
				return '';
		}
	}

	/**
	 * ID column with row actions.
	 *
	 * @param array $item
	 *
	 * @return string
	 */
	public function column_id( $item ) {
		$link_id = Helper::get_data( $item, 'id', 0 );
		$token   = Helper::get_data( $item, 'token', '' );
		$status  = $this->get_item_status( $item );

		$actions = [];

		// Copy Link — only for active links.
		if ( 'active' === $status ) {
			$magic_link_url = add_query_arg( [
				'magic_link'  => '1',
				'magic_token' => $token,
			], home_url() );

			$actions['copy'] = sprintf(
				'<a href="#" class="kc-ml-copy-link" data-magic-url="%s">%s</a>',
				esc_attr( $magic_link_url ),
				__( 'Copy Link', 'magic-link' )
			);
		}

		// Expire — only for active links.
		if ( 'active' === $status ) {
			$expire_url = wp_nonce_url(
				add_query_arg( [
					'page'   => 'magic-link-links',
					'action' => 'expire',
					'id'     => $link_id,
				], admin_url( 'admin.php' ) ),
				'kc_ml_action_nonce'
			);

			$actions['expire'] = sprintf(
				'<a href="%s" onclick="return confirm(\'%s\');">%s</a>',
				esc_url( $expire_url ),
				esc_js( __( 'Are you sure you want to expire this magic link?', 'magic-link' ) ),
				__( 'Expire', 'magic-link' )
			);
		}

		$delete_url = wp_nonce_url(
			add_query_arg( [
				'page'   => 'magic-link-links',
				'action' => 'delete',
				'id'     => $link_id,
			], admin_url( 'admin.php' ) ),
			'kc_ml_action_nonce'
		);

		$actions['delete'] = sprintf(
			'<a href="%s" onclick="return confirm(\'%s\');">%s</a>',
			esc_url( $delete_url ),
			esc_js( __( 'Are you sure you want to delete this magic link?', 'magic-link' ) ),
			__( 'Delete', 'magic-link' )
		);

		return $link_id . $this->row_actions( $actions );
	}

	/**
	 * User column.
	 *
	 * @param array $item
	 *
	 * @return string
	 */
	public function column_user( $item ) {
		$user_id = Helper::get_data( $item, 'user_id', 0 );
		$user    = get_user_by( 'id', $user_id );

		if ( ! $user ) {
			/* translators: %d: user ID */
			return sprintf( __( 'User #%d (deleted)', 'magic-link' ), absint( $user_id ) );
		}

        $html = sprintf(
                '<strong>%s</strong>',
                esc_html( $user->display_name )
        );


        $link_id = Helper::get_data( $item, 'id', 0 );
        $token   = Helper::get_data( $item, 'token', '' );
        $status  = $this->get_item_status( $item );

        $actions = [];

        // Copy Link — only for active links.
        if ( 'active' === $status ) {
            $magic_link_url = add_query_arg( [
                    'magic_link'  => '1',
                    'magic_token' => $token,
            ], home_url() );

            $actions['copy'] = sprintf(
                    '<a href="#" class="kc-ml-copy-link" data-magic-url="%s">%s</a>',
                    esc_attr( $magic_link_url ),
                    __( 'Copy Link', 'magic-link' )
            );
        }

        // Expire — only for active links.
        if ( 'active' === $status ) {
            $expire_url = wp_nonce_url(
                    add_query_arg( [
                            'page'   => 'magic-link-links',
                            'action' => 'expire',
                            'id'     => $link_id,
                    ], admin_url( 'admin.php' ) ),
                    'kc_ml_action_nonce'
            );

            $actions['expire'] = sprintf(
                    '<a href="%s" onclick="return confirm(\'%s\');">%s</a>',
                    esc_url( $expire_url ),
                    esc_js( __( 'Are you sure you want to expire this magic link?', 'magic-link' ) ),
                    __( 'Expire', 'magic-link' )
            );
        }

        $delete_url = wp_nonce_url(
                add_query_arg( [
                        'page'   => 'magic-link-links',
                        'action' => 'delete',
                        'id'     => $link_id,
                ], admin_url( 'admin.php' ) ),
                'kc_ml_action_nonce'
        );

        $actions['delete'] = sprintf(
                '<a href="%s" onclick="return confirm(\'%s\');">%s</a>',
                esc_url( $delete_url ),
                esc_js( __( 'Are you sure you want to delete this magic link?', 'magic-link' ) ),
                __( 'Delete', 'magic-link' )
        );

        return $html . $this->row_actions( $actions );


	}

	/**
	 * Token column.
	 *
	 * @param array $item
	 *
	 * @return string
	 */
	public function column_token( $item ) {
		$token = Helper::get_data( $item, 'token', '' );

		return '<code>' . esc_html( substr( $token, 0, 12 ) ) . '&hellip;</code>';
	}

	/**
	 * Status column.
	 *
	 * @param array $item
	 *
	 * @return string
	 */
	public function column_status( $item ) {
		$status = $this->get_item_status( $item );

		switch ( $status ) {
			case 'used':
				return '<span style="color:#999;font-weight:600;">' . esc_html__( 'Used', 'magic-link' ) . '</span>';
			case 'expired':
				return '<span style="color:#d63638;font-weight:600;">' . esc_html__( 'Expired', 'magic-link' ) . '</span>';
			case 'active':
			default:
				return '<span style="color:#00a32a;font-weight:600;">' . esc_html__( 'Active', 'magic-link' ) . '</span>';
		}
	}

	/**
	 * IP Address column.
	 *
	 * @param array $item
	 *
	 * @return string
	 */
	public function column_ip_address( $item ) {
		$ip = Helper::get_data( $item, 'ip_address', '' );

		return ! empty( $ip ) ? esc_html( $ip ) : '&mdash;';
	}

	/**
	 * Get item status.
	 *
	 * @param array $item
	 *
	 * @return string active|expired|used
	 */
	private function get_item_status( $item ) {
		if ( ! empty( $item['used'] ) ) {
			return 'used';
		}

		if ( strtotime( $item['expires'] ) < time() ) {
			return 'expired';
		}

		return 'active';
	}

	/**
	 * Returns an associative array containing the bulk action
	 *
	 * @return array
	 */
	public function get_bulk_actions() {
        $bulk_actions = [
                'bulk_delete' => __( 'Delete', 'magic-link' ),
        ];

		return apply_filters( 'kc_ml_magic_links_bulk_actions', $bulk_actions );
	}

	/**
	 * Process bulk action
	 *
	 * @since 1.2.1
	 */
	public function process_bulk_action() {
		$action  = Helper::get_request_data( 'action' );
		$action2 = Helper::get_request_data( 'action2' );

		if ( 'expire' === $this->current_action() ) {
			$nonce = Helper::get_request_data( '_wpnonce' );

			if ( ! wp_verify_nonce( $nonce, 'kc_ml_action_nonce' ) ) {
				return;
			}

			$id = absint( Helper::get_request_data( 'id' ) );

			if ( ! empty( $id ) ) {
				global $wpdb;
				$wpdb->update(
					$wpdb->prefix . 'kc_ml_magic_links',
					[ 'expires' => gmdate( 'Y-m-d H:i:s' ) ],
					[ 'id' => $id ],
					[ '%s' ],
					[ '%d' ]
				);
			}
		} elseif ( 'delete' === $this->current_action() ) {
			$nonce = Helper::get_request_data( '_wpnonce' );

			if ( ! wp_verify_nonce( $nonce, 'kc_ml_action_nonce' ) ) {
				return;
			}

			$id = absint( Helper::get_request_data( 'id' ) );

			if ( ! empty( $id ) ) {
				global $wpdb;
				$wpdb->delete( $wpdb->prefix . 'kc_ml_magic_links', [ 'id' => $id ], [ '%d' ] );
			}
		} elseif ( ( 'bulk_delete' === $action ) || ( 'bulk_delete' === $action2 ) ) {
			$nonce       = Helper::get_request_data( '_wpnonce' );
			$nonce_action = 'bulk-' . Helper::get_data( $this->_args, 'plural', '' );

			if ( ! wp_verify_nonce( $nonce, $nonce_action ) ) {
				return;
			}

			$ids = isset( $_POST['magic_link_ids'] ) ? array_map( 'absint', wp_unslash( $_POST['magic_link_ids'] ) ) : [];

			if ( ! empty( $ids ) ) {
				global $wpdb;
				$table = $wpdb->prefix . 'kc_ml_magic_links';

				foreach ( $ids as $id ) {
					$wpdb->delete( $table, [ 'id' => $id ], [ '%d' ] );
				}
			}
		} elseif ( ( 'bulk_mark_used' === $action ) || ( 'bulk_mark_used' === $action2 ) ) {
			$nonce       = Helper::get_request_data( '_wpnonce' );
			$nonce_action = 'bulk-' . Helper::get_data( $this->_args, 'plural', '' );

			if ( ! wp_verify_nonce( $nonce, $nonce_action ) ) {
				return;
			}

			$ids = isset( $_POST['magic_link_ids'] ) ? array_map( 'absint', wp_unslash( $_POST['magic_link_ids'] ) ) : [];

			if ( ! empty( $ids ) ) {
				global $wpdb;
				$table = $wpdb->prefix . 'kc_ml_magic_links';

				foreach ( $ids as $id ) {
					$wpdb->update( $table, [ 'used' => 1 ], [ 'id' => $id ], [ '%d' ], [ '%d' ] );
				}
			}
		} elseif ( ( 'bulk_expire' === $action ) || ( 'bulk_expire' === $action2 ) ) {
			$nonce        = Helper::get_request_data( '_wpnonce' );
			$nonce_action = 'bulk-' . Helper::get_data( $this->_args, 'plural', '' );

			if ( ! wp_verify_nonce( $nonce, $nonce_action ) ) {
				return;
			}

			$ids = isset( $_POST['magic_link_ids'] ) ? array_map( 'absint', wp_unslash( $_POST['magic_link_ids'] ) ) : [];

			if ( ! empty( $ids ) ) {
				global $wpdb;
				$table   = $wpdb->prefix . 'kc_ml_magic_links';
				$now     = gmdate( 'Y-m-d H:i:s' );

				foreach ( $ids as $id ) {
					$wpdb->update( $table, [ 'expires' => $now ], [ 'id' => $id ], [ '%s' ], [ '%d' ] );
				}
			}
		}
	}

	/**
	 * Get lists from the database.
	 *
	 * @param int  $per_page
	 * @param int  $current_page
	 * @param bool $do_count_only
	 *
	 * @return array|int
	 */
	public function get_lists( $per_page = 10, $current_page = 1, $do_count_only = false ) {
		global $wpdb;

		$table       = $wpdb->prefix . 'kc_ml_magic_links';
		$users_table = $wpdb->users;

		$search = Helper::get_request_data( 's' );
		$status = Helper::get_request_data( 'link_status' );

		if ( $do_count_only ) {
			$sql = "SELECT count(*) as total FROM {$table} AS ml LEFT JOIN {$users_table} AS u ON ml.user_id = u.ID";
		} else {
			$sql = "SELECT ml.* FROM {$table} AS ml LEFT JOIN {$users_table} AS u ON ml.user_id = u.ID";
		}

		$args              = [];
		$query             = [];
		$add_where_clause  = false;

		// Search by user email/login/display_name.
		if ( ! empty( $search ) ) {
			$query[] = '(u.user_email LIKE %s OR u.user_login LIKE %s OR u.display_name LIKE %s)';
			$args[]  = '%' . $wpdb->esc_like( $search ) . '%';
			$args[]  = '%' . $wpdb->esc_like( $search ) . '%';
			$args[]  = '%' . $wpdb->esc_like( $search ) . '%';

			$add_where_clause = true;
		}

		// Status filter.
		if ( ! empty( $status ) ) {
			$now = gmdate( 'Y-m-d H:i:s' );
			switch ( $status ) {
				case 'used':
					$query[] = 'ml.used = %d';
					$args[]  = 1;
					break;
				case 'expired':
					$query[] = 'ml.used = %d AND ml.expires < %s';
					$args[]  = 0;
					$args[]  = $now;
					break;
				case 'active':
					$query[] = 'ml.used = %d AND ml.expires >= %s';
					$args[]  = 0;
					$args[]  = $now;
					break;
			}

			$add_where_clause = true;
		}

		if ( $add_where_clause ) {
			$sql .= ' WHERE ';

			if ( count( $query ) > 0 ) {
				$sql .= implode( ' AND ', $query );
				if ( count( $args ) > 0 ) {
					$sql = $wpdb->prepare( $sql, $args );
				}
			}
		}

		if ( ! $do_count_only ) {
			$order    = ! empty( Helper::get_request_data( 'order' ) ) ? strtolower( Helper::get_request_data( 'order' ) ) : 'desc';
			$order_by = sanitize_sql_orderby( Helper::get_request_data( 'orderby' ) );

			$expected_order_values = [ 'asc', 'desc' ];
			if ( ! in_array( $order, $expected_order_values ) ) {
				$order = 'desc';
			}

			$default_order_by          = esc_sql( 'id' );
			$expected_order_by_values  = [ 'id', 'created_at', 'expires' ];

			if ( ! in_array( $order_by, $expected_order_by_values ) ) {
				$order_by_clause = " ORDER BY ml.{$default_order_by} DESC";
			} else {
				$order_by        = esc_sql( $order_by );
				$order_by_clause = " ORDER BY ml.{$order_by} {$order}, ml.{$default_order_by} DESC";
			}

			$sql .= $order_by_clause;
			$sql .= $wpdb->prepare( ' LIMIT %d OFFSET %d', $per_page, ( $current_page - 1 ) * $per_page );

			$result = $wpdb->get_results( $sql, 'ARRAY_A' );
		} else {
			$result = $wpdb->get_var( $sql );
		}

		return $result;
	}

	/**
	 * Search box
	 *
	 * @param string $text
	 * @param string $input_id
	 */
	public function search_box( $text, $input_id ) {
		?>
		<p class="search-box">
			<label class="screen-reader-text"
			       for="<?php echo esc_attr( $input_id ); ?>"><?php echo esc_attr( $text ); ?>:</label>
			<input type="search" id="<?php echo esc_attr( $input_id ); ?>" name="s"
			       value="<?php _admin_search_query(); ?>"/>
			<?php submit_button( __( 'Search Magic Links', 'magic-link' ), 'button', false, false,
				[ 'id' => 'search-submit' ] ); ?>
		</p>
		<?php
	}

	/**
	 * Extra Table Navigation.
	 *
	 * @param string $which
	 *
	 * @return void
	 */
	protected function extra_tablenav( $which ) {
		if ( 'top' !== $which ) {
			return;
		}
		?>
		<div class="alignleft actions">
			<p class="">
				<?php $current_status = Helper::get_request_data( 'link_status', '' ); ?>
				<select name="link_status">
					<option value=""><?php esc_html_e( 'All Statuses', 'magic-link' ); ?></option>
					<option value="active" <?php selected( $current_status, 'active' ); ?>><?php esc_html_e( 'Active', 'magic-link' ); ?></option>
					<option value="expired" <?php selected( $current_status, 'expired' ); ?>><?php esc_html_e( 'Expired', 'magic-link' ); ?></option>
					<option value="used" <?php selected( $current_status, 'used' ); ?>><?php esc_html_e( 'Used', 'magic-link' ); ?></option>
				</select>
				<?php submit_button( __( 'Filter', 'magic-link' ), '', 'filter_action', false, [ 'id' => 'post-query-submit' ] ); ?>
			</p>
		</div>
		<?php
	}

	/**
	 * No items
	 *
	 * @since 1.2.1
	 */
	public function no_items() {
        ?>
        <div class="block ml-auto mr-auto" style="width:50%;">
            <img src="<?php
			echo KC_ML_PLUGIN_ASSETS_DIR_URL . '/images/empty.svg' ?>"/>
        </div>

        <?php
	}
}
