<?php
namespace PpPhp\Plugins;

use PpPhp\Core\ValidationPlugin;

class UniqueRule implements ValidationPlugin
{
    public static function id(): string { return 'unique'; }
    public static function label(): string { return 'Unique (no duplicate)'; }
    public static function group(): string { return 'Data'; }
    public static function paramsSchema(): array { return []; }
    public static function appliesTo(): array { return []; }
    public static function defaultMessage(): string { return '{label} is already taken.'; }

    /**
     * Server-only: queries the table for an existing row with the same value,
     * excluding the current record on edit. $context = { table, field, id }.
     */
    public static function serverCheck(mixed $value, array $params, array $record = [], array $context = []): bool
    {
        $table = preg_replace('/[^A-Za-z0-9_]/', '', (string) ($context['table'] ?? ''));
        $field = preg_replace('/[^A-Za-z0-9_]/', '', (string) ($context['field'] ?? ''));
        if ($table === '' || $field === '') return true; // no context → can't check, don't block

        if (!class_exists('\PpPhp\Core\DB')) return true;

        $sql = "SELECT COUNT(*) AS c FROM `{$table}` WHERE `{$field}` = ?";
        $args = [$value];
        $id = $context['id'] ?? null;
        if ($id !== null && $id !== '') {
            // Exclude the current record on edit, keyed on the table's REAL primary
            // key (not every table uses `id`). pp_pk() ships in generated apps.
            $pk = function_exists('pp_pk') ? pp_pk($table) : 'id';
            $pk = preg_replace('/[^A-Za-z0-9_]/', '', (string) $pk) ?: 'id';
            $sql .= " AND `{$pk}` <> ?";
            $args[] = $id;
        }
        try {
            $rows = \PpPhp\Core\DB::FetchAll($sql, $args);
        } catch (\Throwable $e) {
            return true; // a query failure must never block the save
        }
        return ((int) ($rows[0]['c'] ?? 0)) === 0;
    }

    public static function clientRule(array $params): array
    {
        // Marker so the in-page validator knows this field is unique. It never
        // fails synchronously; the async checker (api/validate-unique.php) stamps
        // the error on blur, and the server enforces it authoritatively on save.
        return ['unique' => true];
    }
}
