<?php
/**
 * Privacy / GDPR integration
 *
 * Registers WordPress Personal Data Exporter and Eraser callbacks so that
 * Tools → Export Personal Data / Erase Personal Data can collect and remove
 * submission log rows linked to a given email address.
 *
 * @package FormConnector
 * @subpackage Privacy
 */

declare(strict_types=1);

namespace FormConnector\Core\Privacy;

use FormConnector\Features\Logs\Logs;
use FormConnector\Features\Attribution\AttributionTracker;

defined('ABSPATH') || exit;

class Privacy {

	/** Per-batch row limit (keeps export/erase chunks bounded). */
	private const BATCH_SIZE = 100;

	/**
	 * Hook into WordPress privacy framework.
	 */
	public static function register(): void {
		add_filter('wp_privacy_personal_data_exporters', [self::class, 'register_exporter']);
		add_filter('wp_privacy_personal_data_erasers', [self::class, 'register_eraser']);
	}

	public static function register_exporter(array $exporters): array {
		$exporters['form-connector-submissions'] = [
			'exporter_friendly_name' => __('CareHQ Connector Submissions', 'form-connector'),
			'callback' => [self::class, 'export_submissions'],
		];
		return $exporters;
	}

	public static function register_eraser(array $erasers): array {
		$erasers['form-connector-submissions'] = [
			'eraser_friendly_name' => __('CareHQ Connector Submissions', 'form-connector'),
			'callback' => [self::class, 'erase_submissions'],
		];
		return $erasers;
	}

	/**
	 * Export submission log rows tied to $email.
	 *
	 * @param string $email Email address being exported.
	 * @param int    $page  1-indexed batch.
	 * @return array{data: array, done: bool}
	 */
	public static function export_submissions(string $email, int $page = 1): array {
		$data_to_export = [];

		$rows = self::query_rows_by_email($email, $page);

		foreach ($rows as $row) {
			$submitted = json_decode((string) ($row['submitted_data'] ?? '{}'), true) ?: [];
			$mapped = is_array($submitted['mapped_to_carehq'] ?? null) ? $submitted['mapped_to_carehq'] : [];

			$item = [
				['name' => __('Submission ID', 'form-connector'), 'value' => (string) ($row['id'] ?? '')],
				['name' => __('Timestamp', 'form-connector'), 'value' => (string) ($row['timestamp'] ?? '')],
				['name' => __('Form', 'form-connector'), 'value' => trim(($row['form_name'] ?? '') . ' (' . ($row['form_plugin'] ?? '') . ')')],
				['name' => __('Status', 'form-connector'), 'value' => (string) ($row['response_status'] ?? '')],
				['name' => __('Location', 'form-connector'), 'value' => (string) ($row['location_name'] ?? '')],
				['name' => __('Email', 'form-connector'), 'value' => (string) ($mapped['email'] ?? '')],
				['name' => __('Phone', 'form-connector'), 'value' => (string) ($mapped['phone'] ?? '')],
				['name' => __('First name', 'form-connector'), 'value' => (string) ($mapped['first_name'] ?? '')],
				['name' => __('Last name', 'form-connector'), 'value' => (string) ($mapped['last_name'] ?? '')],
				['name' => __('UTM source', 'form-connector'), 'value' => (string) ($row['utm_source'] ?? '')],
				['name' => __('UTM medium', 'form-connector'), 'value' => (string) ($row['utm_medium'] ?? '')],
				['name' => __('UTM campaign', 'form-connector'), 'value' => (string) ($row['utm_campaign'] ?? '')],
				['name' => __('Landing page', 'form-connector'), 'value' => (string) ($row['landing_page'] ?? '')],
				['name' => __('Referrer', 'form-connector'), 'value' => (string) ($row['referrer_other'] ?? '')],
			];

			$data_to_export[] = [
				'group_id' => 'form-connector-submissions',
				'group_label' => __('CareHQ Connector Submissions', 'form-connector'),
				'item_id' => 'fc-submission-' . (int) ($row['id'] ?? 0),
				'data' => $item,
			];
		}

		return [
			'data' => $data_to_export,
			'done' => count($rows) < self::BATCH_SIZE,
		];
	}

	/**
	 * Erase submission log rows tied to $email.
	 *
	 * @param string $email Email address being erased.
	 * @param int    $page  1-indexed batch.
	 * @return array{items_removed: int, items_retained: int, messages: array, done: bool}
	 */
	public static function erase_submissions(string $email, int $page = 1): array {
		global $wpdb;

		$rows = self::query_rows_by_email($email, $page);
		$removed = 0;
		$messages = [];

		if (!empty($rows)) {
			$table = Logs::get_instance()->get_table_name();
			$ids = array_map(static fn($r) => (int) ($r['id'] ?? 0), $rows);
			$ids = array_values(array_filter($ids));

			if (!empty($ids)) {
				$placeholders = implode(',', array_fill(0, count($ids), '%d'));
				// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
				$deleted = $wpdb->query($wpdb->prepare(
					"DELETE FROM {$table} WHERE id IN ({$placeholders})",
					$ids
				));
				$removed = (int) $deleted;

				// Also delete related attribution records
				AttributionTracker::get_instance()->delete_by_submission_ids($ids);
			}
		}

		return [
			'items_removed' => $removed,
			'items_retained' => 0,
			'messages' => $messages,
			'done' => count($rows) < self::BATCH_SIZE,
		];
	}

	/**
	 * Fetch a batch of log rows whose stored payload references $email.
	 *
	 * The email lives inside the JSON `submitted_data` column under
	 * `mapped_to_carehq.email`, so we LIKE-match on the JSON blob. This is
	 * intentionally coarse — privacy tooling tolerates over-inclusion better
	 * than under-inclusion.
	 */
	private static function query_rows_by_email(string $email, int $page): array {
		global $wpdb;

		$email = trim($email);
		if ($email === '' || !is_email($email)) {
			return [];
		}

		$table = Logs::get_instance()->get_table_name();
		$page = max(1, $page);
		$offset = ($page - 1) * self::BATCH_SIZE;
		$needle = '%' . $wpdb->esc_like($email) . '%';

		// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
		$sql = $wpdb->prepare(
			"SELECT id, timestamp, form_name, form_plugin, response_status, location_name,
					submitted_data, utm_source, utm_medium, utm_campaign, landing_page, referrer_other
				FROM {$table}
				WHERE submitted_data LIKE %s
				ORDER BY id ASC
				LIMIT %d OFFSET %d",
			$needle,
			self::BATCH_SIZE,
			$offset
		);

		$rows = $wpdb->get_results($sql, ARRAY_A);
		return is_array($rows) ? $rows : [];
	}
}
