<?php

namespace GriffinForms\Includes\Payments;

use GriffinForms\Traits\Singleton;

/**
 * Persists gateway metadata (intents, client secrets, etc.) alongside submissions.
 */
class SubmissionPaymentMeta extends \GriffinForms\Format
{
    use Singleton;

    /**
     * @var string
     */
    protected $submission_table;

    /**
     * Setup submission table reference.
     */
    protected function setSubmissiontable(): void
    {
        $this->submission_table = $this->config->getTable('submission');
    }

    /**
     * Fetch decoded payment metadata for a submission.
     */
    public function getMeta(int $submission_id): array
    {
        if ($submission_id <= 0) {
            return [];
        }

        global $wpdb;
        $raw = $wpdb->get_var(
            $wpdb->prepare(
                "SELECT payment_meta FROM %i WHERE id = %d",
                $this->submission_table,
                $submission_id
            )
        );

        if (empty($raw)) {
            return [];
        }

        $decoded = json_decode($raw, true);
        return is_array($decoded) ? $decoded : [];
    }

    /**
     * Get a single key from the meta blob.
     */
    public function getValue(int $submission_id, string $key, $default = null)
    {
        $meta = $this->getMeta($submission_id);
        return $meta[$key] ?? $default;
    }

    /**
     * Overwrite the meta blob for a submission.
     */
    public function saveMeta(int $submission_id, array $meta): bool
    {
        if ($submission_id <= 0) {
            return false;
        }

        global $wpdb;
        $encoded = wp_json_encode($meta);
        $updated = $wpdb->update(
            $this->submission_table,
            ['payment_meta' => $encoded],
            ['id' => $submission_id],
            ['%s'],
            ['%d']
        );

        return $updated !== false;
    }

    /**
     * Merge new data into the existing meta set.
     */
    public function mergeMeta(int $submission_id, array $payload): bool
    {
        $current = $this->getMeta($submission_id);
        $merged = array_replace_recursive($current, $payload);
        return $this->saveMeta($submission_id, $merged);
    }

    /**
     * Generate and persist a retry token bundle for pending payments.
     */
    public function ensureRetryToken(int $submission_id, int $ttl_hours = 48): ?array
    {
        if ($submission_id <= 0) {
            return null;
        }

        $meta = $this->getMeta($submission_id);
        if (!empty($meta['retry']['token']) && !empty($meta['retry']['expires'])) {
            return $meta['retry'];
        }

        $token = wp_generate_password(40, false, false);
        $expires_ts = current_time('timestamp', true) + ($ttl_hours * HOUR_IN_SECONDS);
        $meta['retry'] = array(
            'token'   => $token,
            'expires' => $expires_ts,
        );

        return $this->saveMeta($submission_id, $meta) ? $meta['retry'] : null;
    }

    /**
     * Validate a retry token bundle.
     */
    public function validateRetryToken(int $submission_id, string $token): ?array
    {
        if ($submission_id <= 0 || $token === '') {
            return null;
        }

        $meta = $this->getMeta($submission_id);
        if (empty($meta['retry']['token']) || empty($meta['retry']['expires'])) {
            return null;
        }

        if (!hash_equals($meta['retry']['token'], $token)) {
            return null;
        }

        $now = current_time('timestamp', true);
        if ((int) $meta['retry']['expires'] > 0 && $meta['retry']['expires'] < $now) {
            return null;
        }

        return $meta['retry'];
    }
}
