<?php
/**
 * WordPress Privacy Tools integration (GDPR / CCPA).
 *
 * Registers Leadite with the core personal-data Exporter and Eraser
 * (Tools → Export Personal Data / Erase Personal Data), so that site
 * owners can fulfil data-subject requests for leads captured by forms:
 * submitted fields, IP address, user agent and other request metadata.
 *
 * Also suggests a paragraph for the site's Privacy Policy page.
 *
 * @package Leadite
 */

namespace Leadite\Privacy;

use Leadite\Storage\LeadsRepository;

defined( 'ABSPATH' ) || exit;

class Privacy {

	/**
	 * Leads processed per batch (core calls us repeatedly until done).
	 */
	const PER_PAGE = 25;

	/**
	 * Hook everything up. Called once from Plugin::boot().
	 *
	 * @return void
	 */
	public static function register() {
		add_filter( 'wp_privacy_personal_data_exporters', array( __CLASS__, 'register_exporter' ) );
		add_filter( 'wp_privacy_personal_data_erasers', array( __CLASS__, 'register_eraser' ) );
		add_action( 'admin_init', array( __CLASS__, 'add_privacy_policy_content' ) );
	}

	/**
	 * Register the personal-data exporter.
	 *
	 * @param array $exporters Registered exporters.
	 * @return array
	 */
	public static function register_exporter( $exporters ) {
		$exporters['leadite-leads'] = array(
			'exporter_friendly_name' => __( 'Leadite form leads', 'leadite' ),
			'callback'               => array( __CLASS__, 'export' ),
		);
		return $exporters;
	}

	/**
	 * Register the personal-data eraser.
	 *
	 * @param array $erasers Registered erasers.
	 * @return array
	 */
	public static function register_eraser( $erasers ) {
		$erasers['leadite-leads'] = array(
			'eraser_friendly_name' => __( 'Leadite form leads', 'leadite' ),
			'callback'             => array( __CLASS__, 'erase' ),
		);
		return $erasers;
	}

	/**
	 * Find submission IDs whose canonical e-mail field matches the address.
	 *
	 * @param string $email_address E-mail address being processed.
	 * @param int    $offset        Query offset (exporter pagination).
	 * @return int[]
	 */
	protected static function find_submission_ids( $email_address, $offset = 0 ) {
		global $wpdb;

		$email = sanitize_email( $email_address );
		if ( '' === $email ) {
			return array();
		}

		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$ids = $wpdb->get_col(
			$wpdb->prepare(
				'SELECT DISTINCT submission_id FROM %i WHERE canonical = %s AND LOWER( field_value ) = LOWER( %s ) ORDER BY submission_id ASC LIMIT %d OFFSET %d',
				LeadsRepository::meta_table(),
				'email',
				$email,
				self::PER_PAGE,
				max( 0, (int) $offset )
			)
		);

		return array_map( 'intval', (array) $ids );
	}

	/**
	 * Exporter callback.
	 *
	 * @param string $email_address E-mail address of the data subject.
	 * @param int    $page          Batch number (1-based).
	 * @return array { data: array, done: bool }
	 */
	public static function export( $email_address, $page = 1 ) {
		$page   = max( 1, (int) $page );
		$offset = ( $page - 1 ) * self::PER_PAGE;
		$ids    = self::find_submission_ids( $email_address, $offset );

		$export_items = array();

		foreach ( $ids as $id ) {
			$found = LeadsRepository::find( $id );
			$row   = $found['row'];
			if ( ! $row ) {
				continue;
			}

			$data = array(
				array(
					'name'  => __( 'Submitted on', 'leadite' ),
					'value' => (string) $row->created_at,
				),
				array(
					'name'  => __( 'Form', 'leadite' ),
					'value' => trim( $row->form_name . ' (' . $row->source . ')' ),
				),
			);

			foreach ( (array) $found['fields'] as $field ) {
				$value = maybe_unserialize( $field->field_value );
				if ( is_array( $value ) || is_object( $value ) ) {
					// Value goes into the WP personal-data exporter array (rendered/escaped by core), not echoed here.
					$value = wp_json_encode( $value, JSON_UNESCAPED_UNICODE );
				}
				$value = trim( (string) $value );
				if ( '' === $value ) {
					continue;
				}
				$label  = '' !== $field->field_label ? $field->field_label : $field->field_key;
				$data[] = array(
					'name'  => $label,
					'value' => $value,
				);
			}

			// Request metadata captured with the submission (personal data too).
			$meta_map = array(
				'ip'         => __( 'IP address', 'leadite' ),
				'user_agent' => __( 'Browser (user agent)', 'leadite' ),
				'page_url'   => __( 'Submitted from page', 'leadite' ),
				'referer'    => __( 'Referrer', 'leadite' ),
				'lang'       => __( 'Language', 'leadite' ),
			);
			foreach ( $meta_map as $prop => $label ) {
				if ( isset( $row->{$prop} ) && '' !== (string) $row->{$prop} ) {
					$data[] = array(
						'name'  => $label,
						'value' => (string) $row->{$prop},
					);
				}
			}

			$export_items[] = array(
				'group_id'          => 'leadite-leads',
				'group_label'       => __( 'Form leads (Leadite)', 'leadite' ),
				'group_description' => __( 'Form submissions captured by the Leadite plugin.', 'leadite' ),
				'item_id'           => 'leadite-lead-' . $id,
				'data'              => $data,
			);
		}

		return array(
			'data' => $export_items,
			'done' => count( $ids ) < self::PER_PAGE,
		);
	}

	/**
	 * Eraser callback.
	 *
	 * Deletes matching leads with the same cascade used by the admin UI:
	 * submission row, submitted fields, notes, activity log, tag relations
	 * and physical attachment files.
	 *
	 * @param string $email_address E-mail address of the data subject.
	 * @param int    $page          Batch number (unused: rows shrink as we delete).
	 * @return array { items_removed: bool, items_retained: bool, messages: array, done: bool }
	 */
	public static function erase( $email_address, $page = 1 ) {
		// Always read from offset 0: every delete shifts the remaining set.
		$ids     = self::find_submission_ids( $email_address, 0 );
		$removed = 0;

		foreach ( $ids as $id ) {
			if ( LeadsRepository::delete( $id ) ) {
				$removed++;
			}
		}

		return array(
			'items_removed'  => $removed > 0,
			'items_retained' => false,
			'messages'       => array(),
			'done'           => count( $ids ) < self::PER_PAGE,
		);
	}

	/**
	 * Suggest a paragraph for the site's Privacy Policy page.
	 *
	 * @return void
	 */
	public static function add_privacy_policy_content() {
		if ( ! function_exists( 'wp_add_privacy_policy_content' ) ) {
			return;
		}

		$content = '<p>' . esc_html__( 'When visitors submit a form on this site, the submitted fields (such as name, e-mail address, phone number and message) together with technical request data (IP address, browser user agent, the page the form was submitted from and the referring page) are stored in the site database so that we can respond to the enquiry.', 'leadite' ) . '</p>'
			. '<p>' . esc_html__( 'This data is kept until it is deleted by a site administrator. It can be exported or erased for a specific e-mail address at any time using the built-in WordPress privacy tools (Tools → Export Personal Data / Erase Personal Data).', 'leadite' ) . '</p>';

		wp_add_privacy_policy_content( 'Leadite', wp_kses_post( $content ) );
	}
}
