<?php
/**
 * Model: Event.php.
 *
 * @package RewardsWP
 */

namespace Awesomemotive\Rewardswp\Models;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

use Awesomemotive\Rewardswp\Abstracts\AbstractModel;
use Awesomemotive\Rewardswp\Database\DatabaseHandler;
use Awesomemotive\Rewardswp\Database\Tables\EventsTable;
use Awesomemotive\Rewardswp\Settings\Options\Referrals\ReferralVariableOption;
use InvalidArgumentException;
use function Awesomemotive\Rewardswp\Helpers\get_option_value;
use function Awesomemotive\Rewardswp\Helpers\get_user_ip;
use function Awesomemotive\Rewardswp\Helpers\is_url;
use function Awesomemotive\Rewardswp\Helpers\remove_url_params;

/**
 * Class Event
 *
 * Represents the event entity and handles database interactions.
 *
 * @since 1.0.0
 */
class Event extends AbstractModel {

	/**
	 * WordPress database handler.
	 *
	 * @since 1.0.0
	 * @var DatabaseHandler
	 */
	protected DatabaseHandler $db_handler;

	/**
	 * Table name.
	 *
	 * @since 1.0.0
	 * @var EventsTable
	 */
	protected EventsTable $db_table;

	/**
	 * Allowed event types.
	 *
	 * @since 1.0.0
	 * @var array
	 */
	private array $allowed_types = [
		'visit',
		'click',
		'share',
	];

	/**
	 * Allowed event contexts.
	 *
	 * @since 1.1.0
	 * @var array
	 */
	private array $allowed_contexts = [
		// Sharing contexts.
		'email',
		'facebook',
		'x',
		'referral_link',
		'panel_launcher',
		'page_view',
	];

	/**
	 * Properties representing referral fields.
	 *
	 * @since 1.0.0
	 * @var int
	 */
	public int $id = 0;

	/**
	 * Member ID if associated with the event.
	 *
	 * @since 1.0.0
	 * @var int|null
	 */
	public ?int $member_id = 0;

	/**
	 * Event type.
	 *
	 * @since 1.0.0
	 * @var string
	 */
	public string $type = 'visit';

	/**
	 * Event context for more granular tracking.
	 *
	 * @since 1.1.0
	 * @var string|null
	 */
	public ?string $context = null;

	/**
	 * Visitor IP address.
	 *
	 * @since 1.0.0
	 * @var string|null
	 */
	public ?string $ip_address = '';

	/**
	 * Referrer URL.
	 *
	 * @since 1.0.0
	 * @var string|null
	 */
	public ?string $referrer_url = '';

	/**
	 * Landing page URL.
	 *
	 * @since 1.0.0
	 * @var string|null
	 */
	public ?string $landing_url = '';

	/**
	 * Creation timestamp.
	 *
	 * @since 1.0.0
	 * @var string
	 */
	public string $created_at = '';

	/**
	 * EventsModel constructor.
	 *
	 * @since 1.0.0
	 *
	 * @param DatabaseHandler $db_handler
	 * @param EventsTable     $db_table
	 */
	public function __construct( DatabaseHandler $db_handler, EventsTable $db_table ) {
		$this->db_handler = $db_handler;
		$this->db_table   = $db_table;
	}

	/**
	 * Retrieve the labels for the model columns and metadata.
	 *
	 * @since 1.0.0
	 * @return array The referral labels.
	 */
	public function get_labels(): array {
		return $this->db_table->get_columns();
	}

	/**
	 * Sanitize data.
	 *
	 * Must be used before saving data into the DB.
	 *
	 * @since 1.0.0
	 * @return void
	 */
	public function sanitize(): void {
		$this->member_id    = absint( $this->member_id );
		$this->type         = sanitize_text_field( $this->type );
		$this->context      = $this->context ? sanitize_text_field( $this->context ) : null;
		$this->ip_address   = sanitize_text_field( $this->ip_address );
		$this->referrer_url = sanitize_text_field( $this->referrer_url );
		$this->landing_url  = sanitize_text_field( $this->landing_url );
		$this->created_at   = sanitize_text_field( $this->created_at );
	}

	/**
	 * Validates the referral data before creating.
	 *
	 * @since 1.0.0
	 *
	 * @return bool When validates successfully.
	 * @throws InvalidArgumentException If validation fails.
	 */
	public function validate_create(): bool {
		if ( empty( $this->member_id ) ) {
			throw new InvalidArgumentException( esc_html__( 'Member ID is required.', 'rewardswp' ) );
		}

		if ( ! in_array( $this->type, $this->allowed_types, true ) ) {
			throw new InvalidArgumentException(
				sprintf(
					/* translators: %s is a placeholder for allowed types */
					esc_html__(
						'Wrong type found. Only %s are allowed.',
						'rewardswp'
					),
					esc_html( implode( ', ', $this->allowed_types ) )
				)
			);
		}

		// Validate context if provided.
		if ( ! empty( $this->context ) && ! in_array( $this->context, $this->allowed_contexts, true ) ) {
			throw new InvalidArgumentException(
				sprintf(
					/* translators: %s is a placeholder for allowed contexts */
					esc_html__(
						'Wrong context found. Only %s are allowed.',
						'rewardswp'
					),
					esc_html( implode( ', ', $this->allowed_contexts ) )
				)
			);
		}

		$params_to_remove_from_url = [
			get_option_value( ReferralVariableOption::class ),
		];

		// Ensure the URL is clean (without any params) before saving.
		$this->referrer_url = remove_url_params(
			is_url( $this->referrer_url )
				? $this->referrer_url
				: '',
			$params_to_remove_from_url
		);

		// Ensure the URL is clean (without any params) before saving.
		$this->landing_url = remove_url_params(
			is_url( $this->landing_url )
				? $this->landing_url
				: '',
			$params_to_remove_from_url
		);

		// If not IP address provided, set the user IP address, no need to trigger errors for this.
		if ( empty( $this->ip_address ) ) {
			$this->ip_address = get_user_ip();
		}

		return true;
	}

	/**
	 * Validates the referral data before updating.
	 *
	 * @since 1.0.0
	 * @return bool When validates successfully.
	 * @throws InvalidArgumentException If validation fails.
	 */
	public function validate_update(): bool {
		// Check if referral ID is provided.
		if ( empty( $this->id ) ) {
			throw new InvalidArgumentException( esc_html__( 'Visit ID is required for updates.', 'rewardswp' ) );
		}

		$this->validate_create();

		return true;
	}
}
