<?php

namespace WPSN\Modules\AI;

defined('ABSPATH') || exit;

/**
 * Lightweight cache for SaaS-managed AI credits.
 *
 * The source of truth is the SaaS backend. We cache locally so the UI can
 * show a balance even when the SaaS is temporarily unavailable.
 */
final class SaaSAICreditsRepository
{
    private const OPTION = 'wpsn_saas_ai_credits_cache';

    /**
     * @return array{balance:float,currency:string,updated_at:int,last_error:string}
     */
    public function get(): array
    {
        $raw = get_option(self::OPTION);
        if (!is_array($raw)) {
            $raw = [];
        }

        $balance = isset($raw['balance']) ? (float) $raw['balance'] : 0.0;
        $currency = isset($raw['currency']) ? sanitize_text_field((string) $raw['currency']) : 'credits';
        $updated = isset($raw['updated_at']) ? (int) $raw['updated_at'] : 0;
        $err = isset($raw['last_error']) ? sanitize_text_field((string) $raw['last_error']) : '';

        return [
            'balance' => $balance,
            'currency' => $currency !== '' ? $currency : 'credits',
            'updated_at' => $updated,
            'last_error' => $err,
        ];
    }

    public function getBalance(): float
    {
        $s = $this->get();
        return (float) ($s['balance'] ?? 0.0);
    }

    /**
     * @param array<string,mixed> $credits
     */
    public function updateFromCreditsArray(array $credits): void
    {
        $balance = 0.0;
        if (isset($credits['balance'])) {
            $balance = (float) $credits['balance'];
        } elseif (isset($credits['remaining'])) {
            $balance = (float) $credits['remaining'];
        }

        $currency = 'credits';
        if (isset($credits['currency'])) {
            $currency = sanitize_text_field((string) $credits['currency']);
        }

        $this->update([
            'balance' => $balance,
            'currency' => $currency !== '' ? $currency : 'credits',
            'updated_at' => time(),
            'last_error' => '',
        ]);
    }

    public function setLastError(string $error): void
    {
        $cur = $this->get();
        $cur['last_error'] = sanitize_text_field($error);
        $cur['updated_at'] = time();
        $this->update($cur);
    }

    public function clear(): void
    {
        delete_option(self::OPTION);
    }

    /**
     * @param array<string,mixed> $state
     */
    private function update(array $state): void
    {
        update_option(self::OPTION, [
            'balance' => isset($state['balance']) ? (float) $state['balance'] : 0.0,
            'currency' => isset($state['currency']) ? sanitize_text_field((string) $state['currency']) : 'credits',
            'updated_at' => isset($state['updated_at']) ? (int) $state['updated_at'] : time(),
            'last_error' => isset($state['last_error']) ? sanitize_text_field((string) $state['last_error']) : '',
        ]);
    }
}
