<?php
/**
 * Content Subscription Manager Class
 *
 * Handles content-based subscription functionality.
 *
 * @link       https://mediahubster.in
 * @since      1.0.4
 *
 * @package    Subs_Sys
 * @subpackage Subs_Sys/includes
 */

// If this file is called directly, abort.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

if ( ! class_exists( 'Subs_Sys_Content_Manager' ) ) {
	/**
	 * Handles content-based subscription management functionality.
	 *
	 * @since      1.0.4
	 * @package    Subs_Sys
	 * @subpackage Subs_Sys/includes
	 * @author     Joe Youngblood <support@subscriptionplugin.com>
	 */
	class Subs_Sys_Content_Manager {

		/**
		 * Track processed posts to prevent duplicate notifications
		 *
		 * @var array
		 */
		private static $processed_posts = array();

		/**
		 * Initialize the class
		 *
		 * @since 1.0.4
		 */
			public function __construct() {
		// Hook into post publishing
		add_action( 'publish_post', array( $this, 'handle_new_content' ), 10, 2 );
		add_action( 'publish_page', array( $this, 'handle_new_content' ), 10, 2 );
		add_action( 'transition_post_status', array( $this, 'handle_post_status_change' ), 10, 3 );
		
		// Handle unsubscribe requests
		add_action( 'init', array( $this, 'handle_unsubscribe_request' ) );
	}

		/**
		 * Create a new content subscription plan
		 *
		 * @param array $plan_data Plan data
		 * @return int|WP_Error Plan ID or WP_Error on failure
		 */
		public function create_content_plan( $plan_data ) {
			global $wpdb;

			// Validate required fields
			if ( empty( $plan_data['plan_name'] ) || empty( $plan_data['content_type'] ) || empty( $plan_data['content_ids'] ) ) {
				return new WP_Error( 'missing_data', __( 'Plan name, content type, and content IDs are required.', 'subscription-system' ) );
			}

			// Prepare data
			$insert_data = array(
				'plan_name'              => sanitize_text_field( $plan_data['plan_name'] ),
				'description'            => wp_kses_post( $plan_data['description'] ?? '' ),
				'price'                  => floatval( $plan_data['price'] ?? 0 ),
				'duration'               => intval( $plan_data['duration'] ?? 30 ),
				'duration_unit'          => sanitize_text_field( $plan_data['duration_unit'] ?? 'days' ),
				'content_type'           => sanitize_text_field( $plan_data['content_type'] ),
				'content_ids'            => is_array( $plan_data['content_ids'] ) ? wp_json_encode( $plan_data['content_ids'] ) : $plan_data['content_ids'],
				'notification_frequency' => sanitize_text_field( $plan_data['notification_frequency'] ?? 'immediate' ),
				'status'                 => sanitize_text_field( $plan_data['status'] ?? 'active' ),
				'stripe_product_id'      => sanitize_text_field( $plan_data['stripe_product_id'] ?? '' ),
				'stripe_price_id'        => sanitize_text_field( $plan_data['stripe_price_id'] ?? '' ),
				'created_at'             => current_time( 'mysql' ),
				'updated_at'             => current_time( 'mysql' )
			);

			$table_name = $wpdb->prefix . 'subscription_content_plans';
			$result = $wpdb->insert( $table_name, $insert_data );

			if ( false === $result ) {
				return new WP_Error( 'db_insert_error', $wpdb->last_error );
			}

			$plan_id = $wpdb->insert_id;

			// Trigger action for other code to run after plan creation
			do_action( 'subs_sys_content_plan_created', $plan_id, $insert_data );

			return $plan_id;
		}

			/**
	 * Get all content subscription plans
	 *
	 * @param array $args Query arguments
	 * @return array Array of content plans
	 */
	public function get_content_plans( $args = array() ) {
		global $wpdb;

		// Check if content tables exist, if not return empty array
		if ( ! Subs_Sys_DB_Updater::content_tables_exist() ) {
			return array();
		}

			$defaults = array(
				'status'       => 'active',
				'content_type' => '',
				'limit'        => 0,
				'offset'       => 0,
				'orderby'      => 'created_at',
				'order'        => 'DESC'
			);

			$args = wp_parse_args( $args, $defaults );
			$table_name = $wpdb->prefix . 'subscription_content_plans';

			// Build WHERE clause
			$where_conditions = array();
			if ( ! empty( $args['status'] ) ) {
				$where_conditions[] = $wpdb->prepare( 'status = %s', $args['status'] );
			}
			if ( ! empty( $args['content_type'] ) ) {
				$where_conditions[] = $wpdb->prepare( 'content_type = %s', $args['content_type'] );
			}

			$where_clause = ! empty( $where_conditions ) ? 'WHERE ' . implode( ' AND ', $where_conditions ) : '';

			// Build ORDER BY clause
			$orderby = sanitize_sql_orderby( $args['orderby'] . ' ' . $args['order'] );
			$order_clause = $orderby ? "ORDER BY $orderby" : '';

			// Build LIMIT clause
			$limit_clause = '';
			if ( $args['limit'] > 0 ) {
				$limit_clause = $wpdb->prepare( 'LIMIT %d', $args['limit'] );
				if ( $args['offset'] > 0 ) {
					$limit_clause = $wpdb->prepare( 'LIMIT %d, %d', $args['offset'], $args['limit'] );
				}
			}

			$sql = "SELECT * FROM $table_name $where_clause $order_clause $limit_clause";
			$plans = $wpdb->get_results( $sql );

			// Decode content_ids for each plan
			foreach ( $plans as $plan ) {
				$plan->content_ids = json_decode( $plan->content_ids, true );
			}

			return $plans ? $plans : array();
		}

			/**
	 * Get a specific content plan by ID
	 *
	 * @param int $plan_id Plan ID
	 * @return object|null Plan object or null if not found
	 */
	public function get_content_plan( $plan_id ) {
		global $wpdb;

		// Check if content tables exist, if not return null
		if ( ! Subs_Sys_DB_Updater::content_tables_exist() ) {
			return null;
		}

			$table_name = $wpdb->prefix . 'subscription_content_plans';
			$plan = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $table_name WHERE id = %d", $plan_id ) );

			if ( $plan ) {
				$plan->content_ids = json_decode( $plan->content_ids, true );
			}

			return $plan;
		}

		/**
		 * Update a content plan
		 *
		 * @param int   $plan_id Plan ID
		 * @param array $plan_data Plan data to update
		 * @return bool|WP_Error True on success, WP_Error on failure
		 */
		public function update_content_plan( $plan_id, $plan_data ) {
			global $wpdb;

			$table_name = $wpdb->prefix . 'subscription_content_plans';

			// Check if plan exists
			$existing_plan = $this->get_content_plan( $plan_id );
			if ( ! $existing_plan ) {
				return new WP_Error( 'plan_not_found', __( 'Content plan not found.', 'subscription-system' ) );
			}

			// Prepare update data
			$update_data = array();
			$allowed_fields = array( 'plan_name', 'description', 'price', 'duration', 'duration_unit', 'content_type', 'content_ids', 'notification_frequency', 'status', 'stripe_product_id', 'stripe_price_id' );

			foreach ( $allowed_fields as $field ) {
				if ( isset( $plan_data[ $field ] ) ) {
					if ( $field === 'content_ids' && is_array( $plan_data[ $field ] ) ) {
						$update_data[ $field ] = wp_json_encode( $plan_data[ $field ] );
					} elseif ( $field === 'price' ) {
						$update_data[ $field ] = floatval( $plan_data[ $field ] );
					} elseif ( $field === 'duration' ) {
						$update_data[ $field ] = intval( $plan_data[ $field ] );
					} elseif ( $field === 'description' ) {
						$update_data[ $field ] = wp_kses_post( $plan_data[ $field ] );
					} else {
						$update_data[ $field ] = sanitize_text_field( $plan_data[ $field ] );
					}
				}
			}

			if ( ! empty( $update_data ) ) {
				$update_data['updated_at'] = current_time( 'mysql' );

				$result = $wpdb->update( $table_name, $update_data, array( 'id' => $plan_id ) );

				if ( false === $result ) {
					return new WP_Error( 'db_update_error', $wpdb->last_error );
				}

				// Trigger action
				do_action( 'subs_sys_content_plan_updated', $plan_id, $update_data );

				return true;
			}

			return true;
		}

		/**
		 * Delete a content plan
		 *
		 * @param int $plan_id Plan ID
		 * @return bool|WP_Error True on success, WP_Error on failure
		 */
		public function delete_content_plan( $plan_id ) {
			global $wpdb;

			// Check if plan exists
			$existing_plan = $this->get_content_plan( $plan_id );
			if ( ! $existing_plan ) {
				return new WP_Error( 'plan_not_found', __( 'Content plan not found.', 'subscription-system' ) );
			}

			$table_name = $wpdb->prefix . 'subscription_content_plans';
			$result = $wpdb->delete( $table_name, array( 'id' => $plan_id ) );

			if ( false === $result ) {
				return new WP_Error( 'db_delete_error', $wpdb->last_error );
			}

			// Also delete related subscriptions and notifications
			$this->cleanup_plan_data( $plan_id );

			// Trigger action
			do_action( 'subs_sys_content_plan_deleted', $plan_id );

			return true;
		}

		/**
		 * Subscribe a user to a content plan
		 *
		 * @param int $user_id User ID
		 * @param int $content_plan_id Content plan ID
		 * @param int $subscription_id Optional regular subscription ID
		 * @return int|WP_Error Content subscription ID or WP_Error on failure
		 */
		public function subscribe_user_to_content( $user_id, $content_plan_id, $subscription_id = null ) {
			global $wpdb;

			// Validate inputs
			$user_id = absint( $user_id );
			$content_plan_id = absint( $content_plan_id );

			if ( empty( $user_id ) || empty( $content_plan_id ) ) {
				return new WP_Error( 'invalid_data', __( 'User ID and content plan ID are required.', 'subscription-system' ) );
			}

			// Check if plan exists
			$plan = $this->get_content_plan( $content_plan_id );
			if ( ! $plan ) {
				return new WP_Error( 'invalid_plan', __( 'Invalid content plan ID', 'subscription-system' ) );
			}

			// Check if user is already subscribed
			$existing_subscription = $this->get_user_content_subscription( $user_id, $content_plan_id );
			if ( $existing_subscription && $existing_subscription->status === 'active' ) {
				return new WP_Error( 'already_subscribed', __( 'User is already subscribed to this content plan.', 'subscription-system' ) );
			}

			// Calculate end date
			$start_date = current_time( 'mysql' );
			$duration = $plan->duration;
			$duration_unit = $plan->duration_unit;

			if ( $duration_unit === 'months' ) {
				$end_timestamp = strtotime( "+{$duration} months", strtotime( $start_date ) );
			} else {
				$end_timestamp = strtotime( "+{$duration} days", strtotime( $start_date ) );
			}
			$end_date = gmdate( 'Y-m-d H:i:s', $end_timestamp );

			// Insert content subscription
			$table_name = $wpdb->prefix . 'subscription_content_subscriptions';
			$insert_data = array(
				'user_id'         => $user_id,
				'content_plan_id' => $content_plan_id,
				'subscription_id' => $subscription_id,
				'status'          => 'active',
				'start_date'      => $start_date,
				'end_date'        => $end_date,
				'created_at'      => current_time( 'mysql' ),
				'updated_at'      => current_time( 'mysql' )
			);

			// Log the data being inserted for debugging
			error_log( 'Content subscription insert data: ' . wp_json_encode( $insert_data ) );

			$result = $wpdb->insert( $table_name, $insert_data );

			if ( false === $result ) {
				error_log( 'Content subscription insert failed: ' . $wpdb->last_error );
				return new WP_Error( 'db_insert_error', $wpdb->last_error );
			}

			$content_subscription_id = $wpdb->insert_id;
			error_log( 'Content subscription created with ID: ' . $content_subscription_id );

			// Trigger action
			do_action( 'subs_sys_user_subscribed_to_content', $content_subscription_id, $user_id, $content_plan_id );

			return $content_subscription_id;
		}

		/**
		 * Get user's content subscription for a specific plan
		 *
		 * @param int $user_id User ID
		 * @param int $content_plan_id Content plan ID
		 * @return object|null Subscription object or null
		 */
		public function get_user_content_subscription( $user_id, $content_plan_id ) {
			global $wpdb;

			$table_name = $wpdb->prefix . 'subscription_content_subscriptions';
			$subscription = $wpdb->get_row( $wpdb->prepare(
				"SELECT * FROM $table_name WHERE user_id = %d AND content_plan_id = %d ORDER BY created_at DESC LIMIT 1",
				$user_id,
				$content_plan_id
			) );

			return $subscription;
		}

		/**
		 * Unsubscribe user from content plan
		 *
		 * @param int $user_id User ID
		 * @param int $content_plan_id Content plan ID
		 * @return bool|WP_Error True on success, WP_Error on failure
		 */
		public function unsubscribe_user_from_content( $user_id, $content_plan_id ) {
			global $wpdb;

			// Validate inputs
			$user_id = absint( $user_id );
			$content_plan_id = absint( $content_plan_id );

			if ( empty( $user_id ) || empty( $content_plan_id ) ) {
				return new WP_Error( 'invalid_data', __( 'User ID and content plan ID are required.', 'subscription-system' ) );
			}

			// Check if user is subscribed
			$subscription = $this->get_user_content_subscription( $user_id, $content_plan_id );
			if ( ! $subscription || $subscription->status !== 'active' ) {
				return new WP_Error( 'not_subscribed', __( 'User is not subscribed to this content plan.', 'subscription-system' ) );
			}

			// Update subscription status to cancelled
			$table_name = $wpdb->prefix . 'subscription_content_subscriptions';
			$result = $wpdb->update(
				$table_name,
				array(
					'status' => 'cancelled',
					'updated_at' => current_time( 'mysql' )
				),
				array(
					'user_id' => $user_id,
					'content_plan_id' => $content_plan_id,
					'status' => 'active'
				),
				array( '%s', '%s' ),
				array( '%d', '%d', '%s' )
			);

			if ( false === $result ) {
				return new WP_Error( 'db_update_error', $wpdb->last_error );
			}

			// Trigger action
			do_action( 'subs_sys_user_unsubscribed_from_content', $subscription->id, $user_id, $content_plan_id );

			return true;
		}

		/**
		 * Get all active content subscriptions for a user
		 *
		 * @param int $user_id User ID
		 * @return array Array of subscription objects
		 */
		public function get_user_active_content_subscriptions( $user_id ) {
			global $wpdb;

			// Check if content tables exist, if not return empty array
			if ( ! Subs_Sys_DB_Updater::content_tables_exist() ) {
				return array();
			}

			$user_id = absint( $user_id );
			if ( empty( $user_id ) ) {
				return array();
			}

			$subscriptions_table = $wpdb->prefix . 'subscription_content_subscriptions';
			$plans_table = $wpdb->prefix . 'subscription_content_plans';

			$subscriptions = $wpdb->get_results( $wpdb->prepare(
				"SELECT cs.*, cp.plan_name, cp.description, cp.content_type, cp.content_ids, cp.notification_frequency, cp.price
				FROM $subscriptions_table cs
				LEFT JOIN $plans_table cp ON cs.content_plan_id = cp.id
				WHERE cs.user_id = %d AND cs.status = 'active'
				ORDER BY cs.created_at DESC",
				$user_id
			) );

			// Decode content_ids for each subscription
			foreach ( $subscriptions as $subscription ) {
				$subscription->content_ids = json_decode( $subscription->content_ids, true );
			}

			return $subscriptions ? $subscriptions : array();
		}

		/**
		 * Get all content subscriptions for a user
		 *
		 * @param int    $user_id User ID
		 * @param string $status Optional status filter
		 * @return array Array of content subscriptions
		 */
		public function get_user_content_subscriptions( $user_id, $status = '' ) {
			global $wpdb;

			$subscriptions_table = $wpdb->prefix . 'subscription_content_subscriptions';
			$plans_table = $wpdb->prefix . 'subscription_content_plans';

			$where_clause = $wpdb->prepare( 'WHERE cs.user_id = %d', $user_id );
			if ( ! empty( $status ) ) {
				$where_clause .= $wpdb->prepare( ' AND cs.status = %s', $status );
			}

			$sql = "SELECT cs.*, cp.plan_name, cp.description, cp.content_type, cp.content_ids, cp.notification_frequency 
					FROM $subscriptions_table cs 
					LEFT JOIN $plans_table cp ON cs.content_plan_id = cp.id 
					$where_clause 
					ORDER BY cs.created_at DESC";

			$subscriptions = $wpdb->get_results( $sql );

			// Decode content_ids for each subscription
			foreach ( $subscriptions as $subscription ) {
				if ( isset( $subscription->content_ids ) ) {
					$subscription->content_ids = json_decode( $subscription->content_ids, true );
				}
			}

			return $subscriptions ? $subscriptions : array();
		}

	/**
	 * Handle new content publication
	 *
	 * @param int     $post_id Post ID
	 * @param WP_Post $post Post object
	 */
	public function handle_new_content( $post_id, $post ) {
		// Prevent duplicate processing for the same post in the same request
		// This can happen when both publish_post and transition_post_status hooks fire
		if ( isset( self::$processed_posts[ $post_id ] ) ) {
			error_log( "Content Manager: Post ID {$post_id} already processed in this request, skipping duplicate notification" );
			return;
		}

		// Mark this post as processed
		self::$processed_posts[ $post_id ] = true;

		error_log( "Content Manager: New content published - Post ID: {$post_id}, Title: {$post->post_title}" );
		
		// Get all active content plans
		$content_plans = $this->get_content_plans( array( 'status' => 'active' ) );
		error_log( "Content Manager: Found " . count( $content_plans ) . " active content plans" );

		foreach ( $content_plans as $plan ) {
			$should_notify = false;

			// Check if this post matches the plan's content criteria
			switch ( $plan->content_type ) {
				case 'category':
					$post_categories = wp_get_post_categories( $post_id );
					$should_notify = ! empty( array_intersect( $plan->content_ids, $post_categories ) );
					if ( $should_notify ) {
						error_log( "Content Manager: Post matches category plan '{$plan->plan_name}' (ID: {$plan->id})" );
					}
					break;

				case 'tag':
					$post_tags = wp_get_post_tags( $post_id, array( 'fields' => 'ids' ) );
					$should_notify = ! empty( array_intersect( $plan->content_ids, $post_tags ) );
					if ( $should_notify ) {
						error_log( "Content Manager: Post matches tag plan '{$plan->plan_name}' (ID: {$plan->id})" );
					}
					break;

				case 'post':
					$should_notify = in_array( $post_id, $plan->content_ids );
					if ( $should_notify ) {
						error_log( "Content Manager: Post matches specific post plan '{$plan->plan_name}' (ID: {$plan->id})" );
					}
					break;

				case 'post_type':
					$should_notify = in_array( $post->post_type, $plan->content_ids );
					if ( $should_notify ) {
						error_log( "Content Manager: Post matches post type plan '{$plan->plan_name}' (ID: {$plan->id})" );
					}
					break;
			}

			if ( $should_notify ) {
				$this->create_content_notifications( $plan->id, $post_id );
			}
		}
	}

		/**
		 * Handle post status changes
		 *
		 * @param string  $new_status New post status
		 * @param string  $old_status Old post status
		 * @param WP_Post $post Post object
		 */
		public function handle_post_status_change( $new_status, $old_status, $post ) {
			// Only handle transitions to published
			if ( $new_status === 'publish' && $old_status !== 'publish' ) {
				$this->handle_new_content( $post->ID, $post );
			}
		}

		/**
		 * Create notifications for subscribers of a content plan
		 *
		 * @param int $content_plan_id Content plan ID
		 * @param int $post_id Post ID
		 */
		private function create_content_notifications( $content_plan_id, $post_id ) {
			global $wpdb;

			// Get all active subscribers to this content plan
			$subscriptions_table = $wpdb->prefix . 'subscription_content_subscriptions';
			$subscribers = $wpdb->get_results( $wpdb->prepare(
				"SELECT user_id FROM $subscriptions_table WHERE content_plan_id = %d AND status = 'active' AND end_date > NOW()",
				$content_plan_id
			) );

			if ( empty( $subscribers ) ) {
				return;
			}

			$notifications_table = $wpdb->prefix . 'subscription_content_notifications';

			foreach ( $subscribers as $subscriber ) {
				// Check if notification already exists
				$existing = $wpdb->get_var( $wpdb->prepare(
					"SELECT id FROM $notifications_table WHERE user_id = %d AND content_plan_id = %d AND post_id = %d",
					$subscriber->user_id,
					$content_plan_id,
					$post_id
				) );

				if ( ! $existing ) {
					$wpdb->insert(
						$notifications_table,
						array(
							'user_id'         => $subscriber->user_id,
							'content_plan_id' => $content_plan_id,
							'post_id'         => $post_id,
							'notification_type' => 'new_content',
							'status'          => 'pending',
							'created_at'      => current_time( 'mysql' )
						)
					);
				}
			}

					// Trigger action for email notifications or other processing
		do_action( 'subs_sys_content_notifications_created', $content_plan_id, $post_id, $subscribers );

		// Send email notifications based on frequency
		$this->process_email_notifications( $content_plan_id, $post_id, $subscribers );
		}

		/**
		 * Get content plans that apply to a specific post
		 *
		 * @param int $post_id Post ID
		 * @return array Array of applicable content plans
		 */
		public function get_applicable_content_plans( $post_id ) {
			$post = get_post( $post_id );
			if ( ! $post ) {
				return array();
			}

			$applicable_plans = array();
			$all_plans = $this->get_content_plans( array( 'status' => 'active' ) );

			foreach ( $all_plans as $plan ) {
				$applies = false;

				switch ( $plan->content_type ) {
					case 'category':
						$post_categories = wp_get_post_categories( $post_id );
						$applies = ! empty( array_intersect( $plan->content_ids, $post_categories ) );
						break;

					case 'tag':
						$post_tags = wp_get_post_tags( $post_id, array( 'fields' => 'ids' ) );
						$applies = ! empty( array_intersect( $plan->content_ids, $post_tags ) );
						break;

					case 'post':
						$applies = in_array( $post_id, $plan->content_ids );
						break;

					case 'post_type':
						$applies = in_array( $post->post_type, $plan->content_ids );
						break;
				}

				if ( $applies ) {
					$applicable_plans[] = $plan;
				}
			}

			return $applicable_plans;
		}

		/**
		 * Check if user is subscribed to any content plan for a specific post
		 *
		 * @param int $user_id User ID
		 * @param int $post_id Post ID
		 * @return bool True if user is subscribed, false otherwise
		 */
		public function is_user_subscribed_to_post_content( $user_id, $post_id ) {
			if ( ! $user_id ) {
				return false;
			}

			$applicable_plans = $this->get_applicable_content_plans( $post_id );
			$user_subscriptions = $this->get_user_content_subscriptions( $user_id, 'active' );

			foreach ( $applicable_plans as $plan ) {
				foreach ( $user_subscriptions as $subscription ) {
					if ( $subscription->content_plan_id == $plan->id ) {
						return true;
					}
				}
			}

			return false;
		}

		/**
		 * Clean up data related to a deleted plan
		 *
		 * @param int $plan_id Plan ID
		 */
		private function cleanup_plan_data( $plan_id ) {
			global $wpdb;

			// Delete content subscriptions
			$wpdb->delete(
				$wpdb->prefix . 'subscription_content_subscriptions',
				array( 'content_plan_id' => $plan_id )
			);

			// Delete notifications
			$wpdb->delete(
				$wpdb->prefix . 'subscription_content_notifications',
				array( 'content_plan_id' => $plan_id )
			);
		}

		/**
		 * Get content type options for admin interface
		 *
		 * @return array Array of content type options
		 */
		public function get_content_type_options() {
			return array(
				'category'  => __( 'Categories', 'subscription-system' ),
				'tag'       => __( 'Tags', 'subscription-system' ),
				'post'      => __( 'Specific Posts', 'subscription-system' ),
				'post_type' => __( 'Post Types', 'subscription-system' )
			);
		}

		/**
		 * Get notification frequency options
		 *
		 * @return array Array of frequency options
		 */
		public function get_notification_frequency_options() {
					return array(
			'immediate' => __( 'Immediate', 'subscription-system' ),
			'daily'     => __( 'Daily Digest', 'subscription-system' ),
			'weekly'    => __( 'Weekly Digest', 'subscription-system' ),
			'monthly'   => __( 'Monthly Digest', 'subscription-system' )
		);
	}

	/**
	 * Process email notifications for content subscribers
	 *
	 * @param int   $content_plan_id Content plan ID
	 * @param int   $post_id Post ID
	 * @param array $subscribers Array of subscriber objects
	 */
	private function process_email_notifications( $content_plan_id, $post_id, $subscribers ) {
		// Get the content plan to check notification frequency
		$plan = $this->get_content_plan( $content_plan_id );
		if ( ! $plan ) {
			return;
		}

		// Only send immediate notifications here
		// Daily, weekly, monthly notifications should be handled by cron jobs
		if ( $plan->notification_frequency !== 'immediate' ) {
			error_log( "Content Manager: Skipping immediate notification (frequency is '{$plan->notification_frequency}'), will be sent via cron" );
			return;
		}

		// Get post details
		$post = get_post( $post_id );
		if ( ! $post ) {
			return;
		}

		// Log how many subscribers will receive emails
		$subscriber_count = count( $subscribers );
		error_log( "Content Manager: Processing email notifications for {$subscriber_count} subscriber(s) for post '{$post->post_title}' (ID: {$post_id})" );

		// Send email to each subscriber
		$sent_count = 0;
		$skipped_count = 0;
		
		foreach ( $subscribers as $subscriber ) {
			$result = $this->send_content_notification_email( $subscriber->user_id, $post, $plan );
			
			if ( $result === 'sent' ) {
				$sent_count++;
			} elseif ( $result === 'skipped' ) {
				$skipped_count++;
			}
		}
		
		// Summary log
		error_log( "Content Manager: Email notification summary - Sent: {$sent_count}, Skipped (duplicates): {$skipped_count}, Total subscribers: {$subscriber_count}" );
	}

	/**
	 * Send content notification email to a user
	 *
	 * @param int     $user_id User ID
	 * @param WP_Post $post Post object
	 * @param object  $plan Content plan object
	 * @return string Status: 'sent', 'skipped', or 'failed'
	 */
	private function send_content_notification_email( $user_id, $post, $plan ) {
		// Check if email notifications are enabled
		if ( ! get_option( 'enable_email_notifications', 1 ) ) {
			error_log( "Content Manager: Email notifications disabled globally" );
			return 'skipped';
		}

		// Get user details
		$user = get_userdata( $user_id );
		if ( ! $user ) {
			error_log( "Content Manager: User {$user_id} not found" );
			return 'failed';
		}

		// DUPLICATE PREVENTION: Check if we've already sent an email for this post to this user
		global $wpdb;
		$email_logs_table = $wpdb->prefix . 'subscription_email_logs';
		
		if ( Subs_Sys_DB_Updater::email_logs_table_exists() ) {
			$already_sent = $wpdb->get_var( $wpdb->prepare(
				"SELECT id FROM $email_logs_table 
				WHERE user_id = %d 
				AND post_id = %d 
				AND email_type = 'content_notification' 
				AND status = 'sent'
				LIMIT 1",
				$user_id,
				$post->ID
			) );

			if ( $already_sent ) {
				error_log( "Content Manager: Email already sent to user {$user_id} ({$user->user_email}) for post {$post->ID}, skipping duplicate" );
				return 'skipped';
			}
		}

		// Prepare email content
		$subject = sprintf(
			/* translators: %1$s: site name, %2$s: post title */
			__( '[%1$s] New Content: %2$s', 'subscription-system' ),
			get_bloginfo( 'name' ),
			$post->post_title
		);

		// Get post excerpt or content
		$post_excerpt = $post->post_excerpt;
		if ( empty( $post_excerpt ) ) {
			$post_excerpt = wp_trim_words( strip_tags( $post->post_content ), 30 );
		}

		// Build email message
		$message = $this->get_notification_email_template( array(
			'user_name'    => $user->display_name,
			'plan_name'    => $plan->plan_name,
			'post_title'   => $post->post_title,
			'post_excerpt' => $post_excerpt,
			'post_url'     => get_permalink( $post->ID ),
			'post_date'    => get_the_date( '', $post->ID ),
			'unsubscribe_url' => $this->get_unsubscribe_url( $user_id, $plan->id )
		) );

		// Set email headers
		$from_email = get_option( 'subscription_from_email', get_option( 'admin_email' ) );
		$from_name = get_option( 'subscription_from_name', get_bloginfo( 'name' ) );
		
		$headers = array(
			'Content-Type: text/html; charset=UTF-8',
			'From: ' . $from_name . ' <' . $from_email . '>'
		);

	// Send email with detailed error logging
	error_log( "→ Sending email to user {$user_id}: {$user->user_email}" );
	error_log( "  Subject: {$subject}" );
	error_log( "  SMTP enabled: " . ( get_option( 'subscription_enable_smtp' ) ? 'Yes' : 'No' ) );
	
	$sent = wp_mail( $user->user_email, $subject, $message, $headers );

	// Prepare email log data
	$email_log_data = array(
		'user_id'          => $user_id,
		'recipient_email'  => $user->user_email,
		'recipient_name'   => $user->display_name,
		'post_id'          => $post->ID,
		'post_title'       => $post->post_title,
		'post_url'         => get_permalink( $post->ID ),
		'content_plan_id'  => $plan->id,
		'subject'          => $subject,
		'email_type'       => 'content_notification',
		'status'           => $sent ? 'sent' : 'failed'
	);

	if ( $sent ) {
		// Mark notification as sent
		$wpdb->update(
			$wpdb->prefix . 'subscription_content_notifications',
			array(
				'sent_at' => current_time( 'mysql' ),
				'status'  => 'sent'
			),
			array(
				'user_id'         => $user_id,
				'content_plan_id' => $plan->id,
				'post_id'         => $post->ID
			)
		);

		// Log successful send to email logs
		Subs_Sys_Email_Logger::log_email( $email_log_data );
		
		error_log( "  ✅ Email sent successfully to {$user->user_email}" );
		
		return 'sent';
	} else {
		// Get the last error from wp_mail
		global $phpmailer;
		$error_message = '';
		if ( isset( $phpmailer ) && ! empty( $phpmailer->ErrorInfo ) ) {
			$error_message = $phpmailer->ErrorInfo;
		}
		
		// Add error message to log data
		$email_log_data['error_message'] = $error_message;
		
		// Log failed send to email logs
		Subs_Sys_Email_Logger::log_email( $email_log_data );
		
		// Log failed send with more details
		error_log( "  ❌ Failed to send email to {$user->user_email}" );
		if ( ! empty( $error_message ) ) {
			error_log( "  Error details: {$error_message}" );
		}
		
		// Log SMTP configuration status for troubleshooting
		if ( get_option( 'subscription_enable_smtp' ) ) {
			$smtp_host = get_option( 'subscription_smtp_host' );
			$smtp_port = get_option( 'subscription_smtp_port' );
			error_log( "  SMTP Config - Host: {$smtp_host}, Port: {$smtp_port}" );
		} else {
			error_log( "  Using PHP mail() function (SMTP not enabled)" );
		}
		
		return 'failed';
	}
}

	/**
	 * Get email template for content notifications
	 *
	 * @param array $args Template arguments
	 * @return string Email HTML content
	 */
	private function get_notification_email_template( $args ) {
		$defaults = array(
			'user_name'       => '',
			'plan_name'       => '',
			'post_title'      => '',
			'post_excerpt'    => '',
			'post_url'        => '',
			'post_date'       => '',
			'unsubscribe_url' => ''
		);

		$args = wp_parse_args( $args, $defaults );

		// Get post by URL to get additional information
		$post_id = url_to_postid( $args['post_url'] );
		$post = $post_id ? get_post( $post_id ) : null;
		
		// Get post thumbnail if available
		$post_thumbnail = '';
		if ( $post && has_post_thumbnail( $post->ID ) ) {
			$post_thumbnail = get_the_post_thumbnail_url( $post->ID, 'large' );
		}

		// Get author information
		$author_name = '';
		$author_avatar = '';
		if ( $post ) {
			$author = get_userdata( $post->post_author );
			if ( $author ) {
				$author_name = $author->display_name;
				$author_avatar = get_avatar_url( $author->ID, array( 'size' => 48 ) );
			}
		}

		// Calculate reading time (average 200 words per minute)
		$word_count = str_word_count( strip_tags( $args['post_excerpt'] ) );
		$reading_time = max( 1, ceil( $word_count / 200 ) );

		ob_start();
		?>
		<!DOCTYPE html>
		<html lang="en">
		<head>
			<meta charset="utf-8">
			<meta name="viewport" content="width=device-width, initial-scale=1.0">
			<meta name="x-apple-disable-message-reformatting">
			<title><?php echo esc_html( $args['post_title'] ); ?></title>
			<!--[if mso]>
			<noscript>
				<xml>
					<o:OfficeDocumentSettings>
						<o:PixelsPerInch>96</o:PixelsPerInch>
					</o:OfficeDocumentSettings>
				</xml>
			</noscript>
			<![endif]-->
			<style>
				/* Reset and base styles */
				body, table, td, p, a, li, blockquote { -webkit-text-size-adjust: 100%; -ms-text-size-adjust: 100%; }
				table, td { mso-table-lspace: 0pt; mso-table-rspace: 0pt; }
				img { -ms-interpolation-mode: bicubic; border: 0; outline: none; text-decoration: none; }
				
				/* Main styles */
				body {
					margin: 0 !important;
					padding: 0 !important;
					background-color: #ffffff;
					font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
					line-height: 1.6;
					color: #292929;
				}
				
				.email-container {
					max-width: 680px;
					margin: 0 auto;
					background-color: #ffffff;
				}
				
				/* Header */
				.email-header {
					padding: 32px 40px 0;
					text-align: center;
					border-bottom: 1px solid #f2f2f2;
				}
				
				.site-logo {
					font-size: 24px;
					font-weight: 700;
					color: #1a8917;
					text-decoration: none;
					margin-bottom: 8px;
					display: inline-block;
				}
				
				.email-tagline {
					font-size: 14px;
					color: #757575;
					margin: 0 0 24px 0;
					font-weight: 400;
				}
				
				/* Main content */
				.email-content {
					padding: 40px 40px 32px;
				}
				
				.greeting {
					font-size: 16px;
					color: #292929;
					margin: 0 0 24px 0;
					font-weight: 400;
				}
				
				.notification-text {
					font-size: 14px;
					color: #757575;
					margin: 0 0 32px 0;
					padding: 16px 20px;
					background-color: #f9f9f9;
					border-radius: 8px;
					border-left: 4px solid #1a8917;
				}
				
				/* Article card */
				.article-card {
					border: 1px solid #f2f2f2;
					border-radius: 12px;
					overflow: hidden;
					margin-bottom: 32px;
					transition: box-shadow 0.15s ease;
				}
				
				.article-card:hover {
					box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
				}
				
				.article-image {
					width: 100%;
					height: 240px;
					object-fit: cover;
					display: block;
				}
				
				.article-content {
					padding: 24px;
				}
				
				.article-title {
					font-size: 22px;
					font-weight: 700;
					line-height: 1.3;
					color: #292929;
					margin: 0 0 12px 0;
					text-decoration: none;
				}
				
				.article-title:hover {
					color: #1a8917;
				}
				
				.article-meta {
					display: flex;
					align-items: center;
					margin-bottom: 16px;
					font-size: 13px;
					color: #757575;
				}
				
				.author-avatar {
					width: 24px;
					height: 24px;
					border-radius: 50%;
					margin-right: 8px;
				}
				
				.article-excerpt {
					font-size: 16px;
					line-height: 1.6;
					color: #292929;
					margin: 0 0 24px 0;
				}
				
				/* CTA Button - Medium style */
				.cta-container {
					text-align: left;
					margin: 32px 0;
				}
				
				.cta-button {
					display: inline-block;
					background-color: #1a8917;
					color: #ffffff !important;
					text-decoration: none;
					font-size: 14px;
					font-weight: 500;
					padding: 12px 24px;
					border-radius: 24px;
					transition: all 0.15s ease;
					border: none;
				}
				
				.cta-button:hover {
					background-color: #156f13;
					transform: translateY(-1px);
					box-shadow: 0 4px 12px rgba(26, 137, 23, 0.3);
				}
				
				/* Divider */
				.divider {
					height: 1px;
					background-color: #f2f2f2;
					margin: 40px 0;
					border: none;
				}
				
				/* Footer */
				.email-footer {
					padding: 0 40px 40px;
					text-align: center;
				}
				
				.footer-text {
					font-size: 13px;
					color: #757575;
					line-height: 1.5;
					margin: 0 0 16px 0;
				}
				
				.unsubscribe-link {
					font-size: 12px;
					color: #9e9e9e;
					text-decoration: none;
					border-bottom: 1px solid transparent;
					transition: all 0.15s ease;
				}
				
				.unsubscribe-link:hover {
					color: #757575;
					border-bottom-color: #757575;
				}
				
				/* Responsive */
				@media only screen and (max-width: 600px) {
					.email-header, .email-content, .email-footer {
						padding-left: 24px !important;
						padding-right: 24px !important;
					}
					
					.article-content {
						padding: 20px !important;
					}
					
					.article-title {
						font-size: 20px !important;
					}
					
					.article-meta {
						flex-wrap: wrap;
					}
				}
				
				/* Dark mode support */
				@media (prefers-color-scheme: dark) {
					.email-container { background-color: #1a1a1a !important; }
					body { background-color: #1a1a1a !important; color: #ffffff !important; }
					.article-title, .greeting, .article-excerpt { color: #ffffff !important; }
					.email-tagline, .notification-text, .footer-text { color: #b3b3b3 !important; }
					.article-card { border-color: #333333 !important; background-color: #1a1a1a !important; }
					.notification-text { background-color: #2a2a2a !important; }
					.divider { background-color: #333333 !important; }
				}
			</style>
		</head>
		<body>
			<div class="email-container">
				<!-- Header -->
				<div class="email-header">
					<a href="<?php echo esc_url( home_url() ); ?>" class="site-logo">
						<?php echo esc_html( get_bloginfo( 'name' ) ); ?>
					</a>
					<p class="email-tagline"><?php esc_html_e( 'Fresh content delivered to your inbox', 'subscription-system' ); ?></p>
				</div>
				
				<!-- Main Content -->
				<div class="email-content">
					<p class="greeting">
						<?php printf( esc_html__( 'Hi %s,', 'subscription-system' ), esc_html( $args['user_name'] ) ); ?>
					</p>
					
					<div class="notification-text">
						<?php printf( 
							esc_html__( '📝 New content published in your "%s" subscription', 'subscription-system' ),
							esc_html( $args['plan_name'] )
						); ?>
					</div>
					
					<!-- Article Card -->
					<div class="article-card">
						<?php if ( $post_thumbnail ): ?>
							<img src="<?php echo esc_url( $post_thumbnail ); ?>" alt="<?php echo esc_attr( $args['post_title'] ); ?>" class="article-image">
						<?php endif; ?>
						
						<div class="article-content">
							<a href="<?php echo esc_url( $args['post_url'] ); ?>" class="article-title">
								<?php echo esc_html( $args['post_title'] ); ?>
							</a>
							
							<div class="article-meta">
								<?php if ( $author_avatar && $author_name ): ?>
									<img src="<?php echo esc_url( $author_avatar ); ?>" alt="<?php echo esc_attr( $author_name ); ?>" class="author-avatar">
									<span><?php echo esc_html( $author_name ); ?></span>
									<span style="margin: 0 8px;">·</span>
								<?php endif; ?>
								<span><?php echo esc_html( $args['post_date'] ); ?></span>
								<?php if ( $reading_time ): ?>
									<span style="margin: 0 8px;">·</span>
									<span><?php printf( esc_html( _n( '%d min read', '%d min read', $reading_time, 'subscription-system' ) ), $reading_time ); ?></span>
								<?php endif; ?>
							</div>
							
							<?php if ( ! empty( $args['post_excerpt'] ) ): ?>
								<p class="article-excerpt"><?php echo esc_html( $args['post_excerpt'] ); ?></p>
							<?php endif; ?>
						</div>
					</div>
					
					<!-- CTA Button -->
					<div class="cta-container">
						<a href="<?php echo esc_url( $args['post_url'] ); ?>" class="cta-button">
							<?php esc_html_e( 'Continue reading', 'subscription-system' ); ?>
						</a>
					</div>
				</div>
				
				<!-- Divider -->
				<hr class="divider">
				
				<!-- Footer -->
				<div class="email-footer">
					<p class="footer-text">
						<?php printf( 
							esc_html__( 'You received this because you\'re subscribed to "%s" on %s', 'subscription-system' ),
							esc_html( $args['plan_name'] ),
							esc_html( get_bloginfo( 'name' ) )
						); ?>
					</p>
					
					<?php if ( ! empty( $args['unsubscribe_url'] ) ): ?>
						<a href="<?php echo esc_url( $args['unsubscribe_url'] ); ?>" class="unsubscribe-link">
							<?php esc_html_e( 'Unsubscribe', 'subscription-system' ); ?>
						</a>
					<?php endif; ?>
				</div>
			</div>
		</body>
		</html>
		<?php
		return ob_get_clean();
	}

	/**
	 * Get unsubscribe URL for a user and content plan
	 *
	 * @param int $user_id User ID
	 * @param int $content_plan_id Content plan ID
	 * @return string Unsubscribe URL
	 */
	private function get_unsubscribe_url( $user_id, $content_plan_id ) {
		return add_query_arg( array(
			'action'          => 'unsubscribe_content',
			'user_id'         => $user_id,
			'content_plan_id' => $content_plan_id,
			'nonce'           => wp_create_nonce( 'unsubscribe_content_' . $user_id . '_' . $content_plan_id )
		), home_url() );
	}

	/**
	 * Handle unsubscribe requests
	 */
	public function handle_unsubscribe_request() {
		if ( ! isset( $_GET['action'] ) || $_GET['action'] !== 'unsubscribe_content' ) {
			return;
		}

		$user_id = isset( $_GET['user_id'] ) ? intval( $_GET['user_id'] ) : 0;
		$content_plan_id = isset( $_GET['content_plan_id'] ) ? intval( $_GET['content_plan_id'] ) : 0;
		$nonce = isset( $_GET['nonce'] ) ? sanitize_text_field( $_GET['nonce'] ) : '';

		// Verify nonce
		if ( ! wp_verify_nonce( $nonce, 'unsubscribe_content_' . $user_id . '_' . $content_plan_id ) ) {
			wp_die( __( 'Invalid security token.', 'subscription-system' ) );
		}

		if ( ! $user_id || ! $content_plan_id ) {
			wp_die( __( 'Invalid unsubscribe request.', 'subscription-system' ) );
		}

		// Update subscription status
		global $wpdb;
		$result = $wpdb->update(
			$wpdb->prefix . 'subscription_content_subscriptions',
			array( 'status' => 'cancelled', 'updated_at' => current_time( 'mysql' ) ),
			array( 'user_id' => $user_id, 'content_plan_id' => $content_plan_id )
		);

		if ( $result ) {
			// Show success message
			wp_die( 
				__( 'You have been successfully unsubscribed from this content plan.', 'subscription-system' ),
				__( 'Unsubscribed', 'subscription-system' ),
				array( 'response' => 200 )
			);
		} else {
			wp_die( __( 'Error processing unsubscribe request.', 'subscription-system' ) );
		}
	}
}
}
