<?php

namespace WPSN\Modules\Stability;

defined('ABSPATH') || exit;

final class SnapshotRepository
{
    public const TYPE_CONFIG = 'config';
    public const TYPE_HEAD = 'head';

    private function tableName(): string
    {
        global $wpdb;
        return $wpdb->prefix . 'wpsn_snapshots';
    }

    /**
     * @param array<string,mixed> $payload
     */
    public function create(string $type, string $label, array $payload, ?int $userId = null, string $pluginVersion = ''): int
    {
        global $wpdb;

        $type = sanitize_key($type);
        if ($type === '') {
            return 0;
        }

        $label = sanitize_text_field($label);
        if ($label === '') {
            $label = ucfirst($type) . ' snapshot';
        }

        $pluginVersion = $pluginVersion !== '' ? $pluginVersion : (string) (defined('WPSN_VERSION') ? WPSN_VERSION : '');

        $encoded = wp_json_encode($payload, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
        if (!is_string($encoded) || $encoded === '') {
            $encoded = '{}';
        }

        $hash = hash('sha256', $encoded);

        $row = [
            'type' => substr($type, 0, 20),
            'label' => substr($label, 0, 191),
            'user_id' => $userId !== null ? (int) $userId : (get_current_user_id() ?: null),
            'plugin_version' => substr($pluginVersion, 0, 32),
            'created_at' => gmdate('Y-m-d H:i:s'),
            'payload' => $encoded,
            'payload_hash' => $hash,
        ];

        $format = ['%s', '%s', '%d', '%s', '%s', '%s', '%s'];

        // Allow NULL user_id.
        if ($row['user_id'] === null) {
            $row['user_id'] = null;
        }

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery
        $wpdb->insert($this->tableName(), $row, $format);

        return (int) $wpdb->insert_id;
    }

    /**
     * @return array<string,mixed>|null
     */
    public function get(int $id): ?array
    {
        global $wpdb;
        $id = (int) $id;
        if ($id <= 0) {
            return null;
        }

        $sql = "SELECT * FROM {$this->tableName()} WHERE id = %d LIMIT 1";
        // phpcs:ignore WordPress.DB.PreparedSQL
        $row = $wpdb->get_row($wpdb->prepare($sql, $id), ARRAY_A);
        if (!is_array($row)) {
            return null;
        }

        $payload = [];
        if (!empty($row['payload'])) {
            $decoded = json_decode((string) $row['payload'], true);
            if (is_array($decoded)) {
                $payload = $decoded;
            }
        }

        $row['payload_decoded'] = $payload;
        return $row;
    }

    /**
     * @return array<int,array<string,mixed>>
     */
    public function list(string $type, int $limit = 20, int $offset = 0): array
    {
        global $wpdb;

        $type = sanitize_key($type);
        if ($type === '') {
            return [];
        }

        $limit = max(1, min(200, $limit));
        $offset = max(0, $offset);

        $sql = "SELECT * FROM {$this->tableName()} WHERE type = %s ORDER BY id DESC LIMIT %d OFFSET %d";
        // phpcs:ignore WordPress.DB.PreparedSQL
        $rows = $wpdb->get_results($wpdb->prepare($sql, $type, $limit, $offset), ARRAY_A);
        return is_array($rows) ? $rows : [];
    }

    public function delete(int $id): bool
    {
        global $wpdb;
        $id = (int) $id;
        if ($id <= 0) {
            return false;
        }

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery
        $wpdb->delete($this->tableName(), ['id' => $id], ['%d']);
        return $wpdb->rows_affected > 0;
    }
}
