<?php
/**
 * MailerPress Add Contact Action
 *
 * Handles adding/updating contacts in MailerPress through SureForms.
 *
 * @package SureForms
 * @since 2.3.0
 */

namespace SRFM_Pro\Inc\Pro\Native_Integrations\Integrations\MailerPress\Actions;

use SRFM_Pro\Inc\Pro\Native_Integrations\WordPress_Action;
use SRFM_Pro\Inc\Traits\Get_Instance;

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

/**
 * Add Contact Action Class
 *
 * @since 2.3.0
 */
class Add_Contact extends WordPress_Action {
	use Get_Instance;

	/**
	 * Integration name
	 *
	 * @var string
	 * @since 2.3.0
	 */
	protected $integration = 'mailerpress';

	/**
	 * Action name
	 *
	 * @var string
	 * @since 2.3.0
	 */
	protected $action = 'add_contact';

	/**
	 * Execute the add contact action
	 *
	 * @param array $data Form submission data.
	 * @return array Action result.
	 * @throws \Exception If contact creation fails.
	 * @since 2.3.0
	 */
	protected function execute( $data ) {
		global $wpdb;

		try {
			// Validate email.
			$email = $data['email'] ?? '';
			if ( empty( $email ) || ! is_email( $email ) ) {
				throw new \Exception( 'Valid email address is required.' );
			}

			// Sanitize input data.
			$email               = sanitize_email( $email );
			$first_name          = sanitize_text_field( $data['first_name'] ?? '' );
			$last_name           = sanitize_text_field( $data['last_name'] ?? '' );
			$subscription_status = sanitize_text_field( $data['subscription_status'] ?? 'subscribed' );
			$lists               = $data['list_ids'] ?? [];
			$tags                = $data['tag_ids'] ?? [];

			// Convert comma-separated string to array if needed.
			if ( is_string( $lists ) ) {
				$lists = array_filter( array_map( 'trim', explode( ',', $lists ) ) );
			}
			if ( is_string( $tags ) ) {
				$tags = array_filter( array_map( 'trim', explode( ',', $tags ) ) );
			}

			// MailerPress table names.
			$contact_table       = $wpdb->prefix . 'mailerpress_contact';
			$contact_lists_table = $wpdb->prefix . 'mailerpress_contact_lists';
			$contact_tags_table  = $wpdb->prefix . 'mailerpress_contact_tags';

			// Check if contact already exists.
			$existing_contact = $wpdb->get_row( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- We need to query custom table and caching is not required.
				$wpdb->prepare(
					// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- We are using prepare correctly here, if we use a placeholder then it will add quotes to the table name.
					"SELECT * FROM {$contact_table} WHERE email = %s",
					$email
				)
			);

			$contact_id = null;
			$is_update  = false;

			if ( $existing_contact ) {
				// Update existing contact.
				$result = $wpdb->update( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- We need to query custom table and caching is not required.
					$contact_table,
					[
						'first_name'          => $first_name,
						'last_name'           => $last_name,
						'subscription_status' => $subscription_status,
						'updated_at'          => current_time( 'mysql' ),
					],
					[ 'contact_id' => $existing_contact->contact_id ],
					[ '%s', '%s', '%s', '%s' ],
					[ '%d' ]
				);

				if ( false === $result ) {
					throw new \Exception( 'Failed to update contact.' );
				}

				$contact_id = $existing_contact->contact_id;
				$is_update  = true;

			} else {
				// Create new contact.
				$unsubscribe_token = wp_generate_uuid4();

				$result = $wpdb->insert( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- We need to add data to a custom table of MailerPress.
					$contact_table,
					[
						'email'               => $email,
						'first_name'          => $first_name,
						'last_name'           => $last_name,
						'subscription_status' => $subscription_status,
						'created_at'          => current_time( 'mysql' ),
						'updated_at'          => current_time( 'mysql' ),
						'unsubscribe_token'   => $unsubscribe_token,
						'opt_in_source'       => '',
						'opt_in_details'      => '',
						'access_token'        => bin2hex( openssl_random_pseudo_bytes( 32 ) ),
					],
					[ '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' ]
				);

				if ( false === $result ) {
					throw new \Exception( 'Failed to create contact.' );
				}

				$contact_id = $wpdb->insert_id;
			}

			// Add contact to lists.
			$lists_added = [];
			if ( ! empty( $lists ) ) {
				foreach ( $lists as $list ) {
					$list_id = $this->process_single_list( $list );

					if ( $list_id > 0 ) {
						// Check if already in list.
						$existing_contact_list = $wpdb->get_row( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- We need to query custom table and caching is not required.
							$wpdb->prepare(
								// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- We are using prepare correctly here, if we use a placeholder then it will add quotes to the table name.
								"SELECT * FROM {$contact_lists_table} WHERE contact_id = %d AND list_id = %d",
								$contact_id,
								$list_id
							)
						);

						if ( ! $existing_contact_list ) {
							$wpdb->insert( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- We need to add data to a custom table of MailerPress.
								$contact_lists_table,
								[
									'contact_id' => $contact_id,
									'list_id'    => $list_id,
								],
								[ '%d', '%d' ]
							);
						}

						$lists_added[] = $list_id;
					}
				}
			}

			// Add contact to tags.
			$tags_added = [];
			if ( ! empty( $tags ) ) {
				foreach ( $tags as $tag ) {
					$tag_id = $this->process_single_tag( $tag );

					if ( $tag_id > 0 ) {
						// Check if already has tag.
						$existing_contact_tag = $wpdb->get_row( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- We need to query custom table and caching is not required.
							$wpdb->prepare(
								// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- We are using prepare correctly here, if we use a placeholder then it will add quotes to the table name.
								"SELECT * FROM {$contact_tags_table} WHERE contact_id = %d AND tag_id = %d",
								$contact_id,
								$tag_id
							)
						);

						if ( ! $existing_contact_tag ) {
							$wpdb->insert( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- We need to add data to a custom table of MailerPress.
								$contact_tags_table,
								[
									'contact_id' => $contact_id,
									'tag_id'     => $tag_id,
								],
								[ '%d', '%d' ]
							);
						}

						$tags_added[] = $tag_id;
					}
				}
			}

			// Get updated contact data.
			$contact = $wpdb->get_row( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- We need to query custom table and caching is not required.
				$wpdb->prepare(
					// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- We are using prepare method and adding placeholder for table name will also add quotes which will give error for the query.
					"SELECT * FROM {$contact_table} WHERE contact_id = %d",
					$contact_id
				)
			);

			$return_data = [
				'contact_id'          => $contact_id,
				'email'               => $contact->email,
				'first_name'          => $contact->first_name,
				'last_name'           => $contact->last_name,
				'full_name'           => trim( $contact->first_name . ' ' . $contact->last_name ),
				'subscription_status' => $contact->subscription_status,
				'created_at'          => $contact->created_at,
				'updated_at'          => $contact->updated_at,
				'lists_added'         => $lists_added,
				'tags_added'          => $tags_added,
				'action_performed'    => $is_update ? 'updated' : 'created',
			];

			$message = $is_update
				? __( 'Contact updated successfully.', 'sureforms-pro' )
				: __( 'Contact created successfully.', 'sureforms-pro' );

			return [
				'success' => true,
				'message' => $message,
				'data'    => $return_data,
			];

		} catch ( \Exception $e ) {
			return [
				'success' => false,
				'message' => sprintf(
					// translators: %s: Error message.
					__( 'Failed to add/update contact: %s', 'sureforms-pro' ),
					$e->getMessage()
				),
			];
		}
	}

	/**
	 * Check if MailerPress plugin is active
	 *
	 * @return bool True if MailerPress is active, false otherwise.
	 * @since 2.3.0
	 */
	protected function is_plugin_active() {
		return defined( 'MAILERPRESS_VERSION' );
	}

	/**
	 * Process a single list and return its ID (create if needed)
	 *
	 * @param mixed $list List data.
	 * @return int List ID or 0 if failed.
	 * @since 2.3.0
	 */
	private function process_single_list( $list ) {
		global $wpdb;

		$list_id = 0;

		// Check if list is an ID or name.
		if ( is_array( $list ) ) {
			if ( isset( $list['value'] ) && ! empty( $list['value'] ) ) {
				$list_id = absint( $list['value'] );
			} elseif ( isset( $list['id'] ) && ! empty( $list['id'] ) ) {
				$list_id = absint( $list['id'] );
			} elseif ( isset( $list['name'] ) && ! empty( $list['name'] ) ) {
				// Search for list by name.
				$existing_list = $wpdb->get_row( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- We need to query custom table and caching is not required.
					$wpdb->prepare(
						"SELECT list_id FROM {$wpdb->prefix}mailerpress_lists WHERE name = %s",
						sanitize_text_field( $list['name'] )
					)
				);

				if ( $existing_list ) {
					$list_id = $existing_list->list_id;
				} else {
					// Create new list.
					$new_list_result = $wpdb->insert( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- We need to add data to a custom table of MailerPress.
						$wpdb->prefix . 'mailerpress_lists',
						[
							'name'        => sanitize_text_field( $list['name'] ),
							'description' => '',
							'created_at'  => current_time( 'mysql' ),
							'updated_at'  => current_time( 'mysql' ),
						],
						[ '%s', '%s', '%s', '%s' ]
					);

					if ( $new_list_result ) {
						$list_id = $wpdb->insert_id;
					}
				}
			}
		} elseif ( is_numeric( $list ) ) {
			$list_id = absint( $list );
		} elseif ( is_string( $list ) ) {
			// Search for list by name.
			$existing_list = $wpdb->get_row( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- We need to query custom table and caching is not required.
				$wpdb->prepare(
					"SELECT list_id FROM {$wpdb->prefix}mailerpress_lists WHERE name = %s",
					sanitize_text_field( $list )
				)
			);

			if ( $existing_list ) {
				$list_id = $existing_list->list_id;
			} else {
				// Create new list.
				$new_list_result = $wpdb->insert( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- We need to add data to a custom table of MailerPress.
					$wpdb->prefix . 'mailerpress_lists',
					[
						'name'        => sanitize_text_field( $list ),
						'description' => '',
						'created_at'  => current_time( 'mysql' ),
						'updated_at'  => current_time( 'mysql' ),
					],
					[ '%s', '%s', '%s', '%s' ]
				);

				if ( $new_list_result ) {
					$list_id = $wpdb->insert_id;
				}
			}
		}

		return $list_id;
	}

	/**
	 * Process a single tag and return its ID (create if needed)
	 *
	 * @param mixed $tag Tag data.
	 * @return int Tag ID or 0 if failed.
	 * @since 2.3.0
	 */
	private function process_single_tag( $tag ) {
		global $wpdb;

		$tag_id = 0;

		// Check if tag is an ID or name.
		if ( is_array( $tag ) ) {
			if ( isset( $tag['value'] ) && ! empty( $tag['value'] ) ) {
				$tag_id = absint( $tag['value'] );
			} elseif ( isset( $tag['id'] ) && ! empty( $tag['id'] ) ) {
				$tag_id = absint( $tag['id'] );
			} elseif ( isset( $tag['name'] ) && ! empty( $tag['name'] ) ) {
				// Search for tag by name.
				$existing_tag = $wpdb->get_row( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- We need to query custom table and caching is not required.
					$wpdb->prepare(
						"SELECT tag_id FROM {$wpdb->prefix}mailerpress_tags WHERE name = %s",
						sanitize_text_field( $tag['name'] )
					)
				);

				if ( $existing_tag ) {
					$tag_id = $existing_tag->tag_id;
				} else {
					// Create new tag.
					$new_tag_result = $wpdb->insert( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- We need to add data to a custom table of MailerPress.
						$wpdb->prefix . 'mailerpress_tags',
						[
							'name' => sanitize_text_field( $tag['name'] ),
						],
						[ '%s' ]
					);

					if ( $new_tag_result ) {
						$tag_id = $wpdb->insert_id;
					}
				}
			}
		} elseif ( is_numeric( $tag ) ) {
			$tag_id = absint( $tag );
		} elseif ( is_string( $tag ) ) {
			// Search for tag by name.
			$existing_tag = $wpdb->get_row( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- We need to query custom table and caching is not required.
				$wpdb->prepare(
					"SELECT tag_id FROM {$wpdb->prefix}mailerpress_tags WHERE name = %s",
					sanitize_text_field( $tag )
				)
			);

			if ( $existing_tag ) {
				$tag_id = $existing_tag->tag_id;
			} else {
				// Create new tag.
				$new_tag_result = $wpdb->insert( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- We need to add data to a custom table of MailerPress.
					$wpdb->prefix . 'mailerpress_tags',
					[
						'name' => sanitize_text_field( $tag ),
					],
					[ '%s' ]
				);

				if ( $new_tag_result ) {
					$tag_id = $wpdb->insert_id;
				}
			}
		}

		return $tag_id;
	}
}

// Initialize the class.
Add_Contact::get_instance();
