<?php
/**
 * Page Access Control Class
 *
 * Handles page-level access control with custom rules
 *
 * @package KarateClubManager
 */

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

/**
 * Page Access Class
 */
class MACM_Page_Access {

	/**
	 * Get page access configuration
	 *
	 * @param int $page_id WordPress page ID.
	 * @return object|null Page access object or null if not protected.
	 */
	public static function get_page_access( $page_id ) {
		global $wpdb;

		$page_access = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT * FROM {$wpdb->prefix}macm_page_access WHERE page_id = %d",
				$page_id
			)
		);

		return $page_access ? $page_access : null;
	}

	/**
	 * Save or update page access configuration
	 *
	 * @param int    $page_id     WordPress page ID.
	 * @param string $access_type Access type: 'login_required' or 'custom'.
	 * @param array  $rules       Array of rules: [['type' => 'user', 'value' => 1], ...].
	 * @return bool|WP_Error True on success, WP_Error on failure.
	 */
	public static function save_page_access( $page_id, $access_type, $rules = array() ) {
		global $wpdb;

		// Validate page exists.
		$page = get_post( $page_id );
		if ( ! $page || 'page' !== $page->post_type ) {
			return new WP_Error( 'invalid_page', __( 'Invalid page ID.', 'martial-arts-club-manager' ) );
		}

		// Validate access type.
		if ( ! in_array( $access_type, array( 'login_required', 'custom' ), true ) ) {
			return new WP_Error( 'invalid_access_type', __( 'Invalid access type.', 'martial-arts-club-manager' ) );
		}

		// Validate rules if custom access.
		if ( 'custom' === $access_type && empty( $rules ) ) {
			return new WP_Error( 'missing_rules', __( 'Custom access type requires at least one rule.', 'martial-arts-club-manager' ) );
		}

		// Check if page access already exists.
		$existing = self::get_page_access( $page_id );

		if ( $existing ) {
			// Update existing record.
			$updated = $wpdb->update(
				$wpdb->prefix . 'macm_page_access',
				array(
					'access_type' => $access_type,
					'updated_at'  => current_time( 'mysql' ),
				),
				array( 'page_id' => $page_id ),
				array( '%s', '%s' ),
				array( '%d' )
			);

			if ( false === $updated ) {
				return new WP_Error( 'db_error', __( 'Failed to update page access.', 'martial-arts-club-manager' ) );
			}

			$page_access_id = $existing->id;
		} else {
			// Insert new record.
			$inserted = $wpdb->insert(
				$wpdb->prefix . 'macm_page_access',
				array(
					'page_id'     => $page_id,
					'access_type' => $access_type,
				),
				array( '%d', '%s' )
			);

			if ( ! $inserted ) {
				return new WP_Error( 'db_error', __( 'Failed to create page access.', 'martial-arts-club-manager' ) );
			}

			$page_access_id = $wpdb->insert_id;
		}

		// Delete existing rules.
		$wpdb->delete(
			$wpdb->prefix . 'macm_page_access_rules',
			array( 'page_access_id' => $page_access_id ),
			array( '%d' )
		);

		// Insert new rules if custom access.
		if ( 'custom' === $access_type && ! empty( $rules ) ) {
			foreach ( $rules as $rule ) {
				if ( ! isset( $rule['type'] ) || ! isset( $rule['value'] ) ) {
					continue;
				}

				// Validate rule type.
				if ( ! in_array( $rule['type'], array( 'user', 'membership_type', 'group' ), true ) ) {
					continue;
				}

				// Validate rule value.
				$rule_value = absint( $rule['value'] );
				if ( $rule_value <= 0 ) {
					continue;
				}

				$wpdb->insert(
					$wpdb->prefix . 'macm_page_access_rules',
					array(
						'page_access_id' => $page_access_id,
						'rule_type'      => $rule['type'],
						'rule_value'     => $rule_value,
					),
					array( '%d', '%s', '%d' )
				);
			}
		}

		return true;
	}

	/**
	 * Delete page access configuration
	 *
	 * @param int $page_id WordPress page ID.
	 * @return bool True on success, false on failure.
	 */
	public static function delete_page_access( $page_id ) {
		global $wpdb;

		// Get page access record.
		$page_access = self::get_page_access( $page_id );
		if ( ! $page_access ) {
			return true; // Already deleted.
		}

		// Delete rules first.
		$wpdb->delete(
			$wpdb->prefix . 'macm_page_access_rules',
			array( 'page_access_id' => $page_access->id ),
			array( '%d' )
		);

		// Delete page access.
		$deleted = $wpdb->delete(
			$wpdb->prefix . 'macm_page_access',
			array( 'page_id' => $page_id ),
			array( '%d' )
		);

		return false !== $deleted;
	}

	/**
	 * Get all protected pages
	 *
	 * @return array Array of page access objects with page details.
	 */
	public static function get_all_protected_pages() {
		global $wpdb;

		$results = $wpdb->get_results(
			"SELECT pa.*, p.post_title
			FROM {$wpdb->prefix}macm_page_access pa
			INNER JOIN {$wpdb->posts} p ON pa.page_id = p.ID
			WHERE p.post_type = 'page' AND p.post_status = 'publish'
			ORDER BY p.post_title ASC"
		);

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

	/**
	 * Get rules for a page
	 *
	 * @param int $page_id WordPress page ID.
	 * @return array Array of rule objects.
	 */
	public static function get_page_rules( $page_id ) {
		global $wpdb;

		// Get page access record.
		$page_access = self::get_page_access( $page_id );
		if ( ! $page_access ) {
			return array();
		}

		// Get rules.
		$rules = $wpdb->get_results(
			$wpdb->prepare(
				"SELECT * FROM {$wpdb->prefix}macm_page_access_rules
				WHERE page_access_id = %d
				ORDER BY id ASC",
				$page_access->id
			)
		);

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

	/**
	 * Check if user has access to a page
	 *
	 * @param int $page_id WordPress page ID.
	 * @param int $user_id WordPress user ID (0 for current user).
	 * @return bool True if user has access, false otherwise.
	 */
	public static function check_user_access( $page_id, $user_id = 0 ) {
		// Get user ID if not provided.
		if ( 0 === $user_id ) {
			$user_id = get_current_user_id();
		}

		// Get page access configuration.
		$page_access = self::get_page_access( $page_id );

		// If page is not protected, allow access.
		if ( ! $page_access ) {
			return true;
		}

		// For 'login_required', check if user is logged in.
		if ( 'login_required' === $page_access->access_type ) {
			return $user_id > 0;
		}

		// For 'custom', check if user is logged in first.
		if ( 0 === $user_id ) {
			return false;
		}

		// Get rules.
		$rules = self::get_page_rules( $page_id );

		// If no rules defined, deny access (custom should have rules).
		if ( empty( $rules ) ) {
			return false;
		}

		// Check each rule (OR logic - user passes if ANY rule matches).
		foreach ( $rules as $rule ) {
			if ( self::check_rule_match( $rule, $user_id ) ) {
				return true;
			}
		}

		// No rule matched.
		return false;
	}

	/**
	 * Check if a specific rule matches for a user
	 *
	 * @param object $rule    Rule object with rule_type and rule_value.
	 * @param int    $user_id WordPress user ID.
	 * @return bool True if rule matches, false otherwise.
	 */
	private static function check_rule_match( $rule, $user_id ) {
		switch ( $rule->rule_type ) {
			case 'user':
				// Direct user ID match.
				return (int) $rule->rule_value === (int) $user_id;

			case 'membership_type':
				// Check if user has a member with this membership type.
				return self::user_has_membership_type( $user_id, $rule->rule_value );

			case 'group':
				// Check if user has a member in this group.
				return self::user_has_group( $user_id, $rule->rule_value );

			default:
				return false;
		}
	}

	/**
	 * Check if user has a member with specific membership type
	 *
	 * Checks if ANY active member belonging to the user has the specified membership type.
	 * This allows access if at least one family member has the required membership,
	 * even if other members have different membership levels.
	 * Only active members are considered; archived members are excluded.
	 *
	 * @param int $user_id           WordPress user ID.
	 * @param int $membership_type_id Membership type ID.
	 * @return bool True if user has at least one active member with this type, false otherwise.
	 */
	private static function user_has_membership_type( $user_id, $membership_type_id ) {
		global $wpdb;

		$count = $wpdb->get_var(
			$wpdb->prepare(
				"SELECT COUNT(*) FROM {$wpdb->prefix}macm_members
				WHERE user_id = %d AND membership_type_id = %d AND status = 'active'",
				$user_id,
				$membership_type_id
			)
		);

		return $count > 0;
	}

	/**
	 * Check if user has a member in specific group
	 *
	 * Uses the member_groups junction table to support many-to-many relationships.
	 * Checks if ANY active member belonging to the user is in the specified group.
	 * Only active members are considered; archived members are excluded.
	 *
	 * @param int $user_id  WordPress user ID.
	 * @param int $group_id Group ID.
	 * @return bool True if user has active member in this group, false otherwise.
	 */
	private static function user_has_group( $user_id, $group_id ) {
		global $wpdb;

		// Query using the member_groups junction table.
		$count = $wpdb->get_var(
			$wpdb->prepare(
				"SELECT COUNT(DISTINCT mg.member_id)
				FROM {$wpdb->prefix}macm_member_groups mg
				INNER JOIN {$wpdb->prefix}macm_members m ON mg.member_id = m.id
				WHERE m.user_id = %d AND mg.group_id = %d AND m.status = 'active'",
				$user_id,
				$group_id
			)
		);

		return $count > 0;
	}

	/**
	 * Check if a page is protected
	 *
	 * @param int $page_id WordPress page ID.
	 * @return bool True if protected, false otherwise.
	 */
	public static function is_page_protected( $page_id ) {
		$page_access = self::get_page_access( $page_id );
		return null !== $page_access;
	}
}
