<?php

namespace App\Services\Stripe;

/**
 * A Stripe that records what it was asked to do.
 *
 * The catalogue sync has to be exercised for real — it is the thing that must
 * be idempotent and must never mint a second Price for the same row — and that
 * is testable without a network. Ids are deterministic so a test can assert
 * which product a price was attached to.
 */
class FakeStripeClient implements StripeClient
{
    public bool $configured = true;

    /** @var array<int, array{name: string, metadata: array}> */
    public array $products = [];

    /** @var array<int, array{product: string, amount: int, currency: string, interval: string, metadata: array}> */
    public array $prices = [];

    /** @var array<int, string> */
    public array $archived = [];

    /** Idempotency key → the id first returned for it. @var array<string, string> */
    public array $keys = [];

    public function isConfigured(): bool
    {
        return $this->configured;
    }

    public function createProduct(string $name, array $metadata = [], ?string $idempotencyKey = null): string
    {
        // Replays the first answer for a repeated key, as Stripe does.
        if ($idempotencyKey !== null && isset($this->keys[$idempotencyKey])) {
            return $this->keys[$idempotencyKey];
        }

        $id = 'prod_'.substr(sha1($name.count($this->products)), 0, 12);
        $this->products[$id] = ['name' => $name, 'metadata' => $metadata];

        if ($idempotencyKey !== null) {
            $this->keys[$idempotencyKey] = $id;
        }

        return $id;
    }

    public function createPrice(
        string $productId,
        int $amountCents,
        string $currency,
        string $interval,
        array $metadata = [],
        ?string $idempotencyKey = null,
    ): string {
        if ($idempotencyKey !== null && isset($this->keys[$idempotencyKey])) {
            return $this->keys[$idempotencyKey];
        }

        $id = 'price_'.substr(sha1($productId.$amountCents.$interval.count($this->prices)), 0, 12);
        $this->prices[$id] = [
            'product' => $productId,
            'amount' => $amountCents,
            'currency' => $currency,
            'interval' => $interval,
            'metadata' => $metadata,
        ];

        if ($idempotencyKey !== null) {
            $this->keys[$idempotencyKey] = $id;
        }

        return $id;
    }

    public function archivePrice(string $priceId): void
    {
        $this->archived[] = $priceId;
    }
}
