<?php
/**
 * Personal data export and erasure, through the native WordPress tools.
 *
 * @package SkyServers\Retragere
 */

declare(strict_types=1);

namespace SkyServers\Retragere\Wp;

use WP_Query;

/**
 * Erasure anonymises identity but keeps the record. A withdrawal declaration is
 * evidence of processing, and an erasure request must not become a way to
 * destroy it.
 */
final class Privacy
{
    private const PER_PAGE = 20;

    public static function register(): void
    {
        add_filter('wp_privacy_personal_data_exporters', [self::class, 'registerExporter']);
        add_filter('wp_privacy_personal_data_erasers', [self::class, 'registerEraser']);
    }

    /**
     * @param array<string,mixed> $exporters
     *
     * @return array<string,mixed>
     */
    public static function registerExporter(array $exporters): array
    {
        $exporters['skyservers-retragere-contract'] = [
            'exporter_friendly_name' => __('Contract withdrawal requests', 'skyservers-retragere-contract'),
            'callback'               => [self::class, 'export'],
        ];

        return $exporters;
    }

    /**
     * @param array<string,mixed> $erasers
     *
     * @return array<string,mixed>
     */
    public static function registerEraser(array $erasers): array
    {
        $erasers['skyservers-retragere-contract'] = [
            'eraser_friendly_name' => __('Contract withdrawal requests', 'skyservers-retragere-contract'),
            'callback'             => [self::class, 'erase'],
        ];

        return $erasers;
    }

    /**
     * @return array{data:array<int,array<string,mixed>>,done:bool}
     */
    public static function export(string $email, int $page = 1): array
    {
        $items = [];

        foreach (self::query($email, $page) as $id) {
            $items[] = [
                'group_id'    => 'ssrc-requests',
                'group_label' => __('Contract withdrawal requests', 'skyservers-retragere-contract'),
                'item_id'     => 'ssrc-request-' . $id,
                'data'        => [
                    [
                        'name'  => __('Reference', 'skyservers-retragere-contract'),
                        'value' => Repository::reference($id),
                    ],
                    [
                        'name'  => __('Name', 'skyservers-retragere-contract'),
                        'value' => (string) get_post_meta($id, Repository::META_NAME, true),
                    ],
                    [
                        'name'  => __('Email', 'skyservers-retragere-contract'),
                        'value' => (string) get_post_meta($id, Repository::META_EMAIL, true),
                    ],
                    [
                        'name'  => __('Order / contract', 'skyservers-retragere-contract'),
                        'value' => (string) get_post_meta($id, Repository::META_REF, true),
                    ],
                    [
                        'name'  => __('IP address', 'skyservers-retragere-contract'),
                        'value' => (string) get_post_meta($id, Repository::META_IP, true),
                    ],
                    [
                        'name'  => __('Declaration', 'skyservers-retragere-contract'),
                        'value' => (string) get_post_field('post_content', $id),
                    ],
                    [
                        'name'  => __('Submitted at', 'skyservers-retragere-contract'),
                        'value' => (string) get_post_field('post_date_gmt', $id) . ' UTC',
                    ],
                ],
            ];
        }

        return [
            'data' => $items,
            'done' => count($items) < self::PER_PAGE,
        ];
    }

    /**
     * @return array{items_removed:bool,items_retained:bool,messages:string[],done:bool}
     */
    public static function erase(string $email, int $page = 1): array
    {
        $ids = self::query($email, $page);

        foreach ($ids as $id) {
            update_post_meta($id, Repository::META_NAME, __('(anonymised)', 'skyservers-retragere-contract'));
            update_post_meta($id, Repository::META_EMAIL, '');
            update_post_meta($id, Repository::META_IP, '');
            update_post_meta($id, Repository::META_UA, '');
        }

        return [
            'items_removed'  => false,
            'items_retained' => [] !== $ids,
            'messages'       => [] === $ids ? [] : [
                __('The identifying details have been anonymised. The withdrawal request and the content of the declaration are kept, as evidence of a legal obligation.', 'skyservers-retragere-contract'),
            ],
            'done'           => count($ids) < self::PER_PAGE,
        ];
    }

    /**
     * @return int[]
     */
    private static function query(string $email, int $page): array
    {
        $query = new WP_Query(
            [
                'post_type'      => PostType::NAME,
                'post_status'    => array_keys(PostType::statusLabels()),
                'posts_per_page' => self::PER_PAGE,
                'paged'          => max(1, $page),
                'fields'         => 'ids',
                // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query -- bounded lookup on a small post type.
                'meta_query'     => [
                    [
                        'key'   => Repository::META_EMAIL,
                        'value' => $email,
                    ],
                ],
            ]
        );

        return array_map('intval', $query->posts);
    }
}
