<?php

namespace App\Modules\Integrations\Platform\Repositories;

use App\Modules\Integrations\Platform\Models\ApiIdempotencyKey;
use Illuminate\Database\QueryException;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;

final class ApiIdempotencyRepository
{
    /**
     * @return array{state:'reserved', id:int}|array{state:'replay', status:int, body:string}|array{state:'conflict'}|array{state:'in_flight'}
     */
    public function reserveOrResolve(
        int $tenantId,
        int $apiTokenId,
        string $method,
        string $pathSignature,
        string $idempotencyKey,
        string $bodyHash,
        Carbon $expiresAt,
    ): array {
        return DB::transaction(function () use ($tenantId, $apiTokenId, $method, $pathSignature, $idempotencyKey, $bodyHash, $expiresAt): array {
            $existing = ApiIdempotencyKey::query()
                ->where('api_token_id', $apiTokenId)
                ->where('path_signature', $pathSignature)
                ->where('idempotency_key', $idempotencyKey)
                ->lockForUpdate()
                ->first();

            if ($existing instanceof ApiIdempotencyKey) {
                if ($existing->body_hash !== $bodyHash) {
                    return ['state' => 'conflict'];
                }
                if ($existing->response_status === null) {
                    return ['state' => 'in_flight'];
                }

                return [
                    'state' => 'replay',
                    'status' => (int) $existing->response_status,
                    'body' => (string) $existing->response_body,
                ];
            }

            try {
                $row = ApiIdempotencyKey::query()->create([
                    'tenant_id' => $tenantId,
                    'api_token_id' => $apiTokenId,
                    'method' => $method,
                    'path_signature' => $pathSignature,
                    'idempotency_key' => $idempotencyKey,
                    'body_hash' => $bodyHash,
                    'response_status' => null,
                    'response_body' => null,
                    'expires_at' => $expiresAt,
                    'created_at' => now(),
                ]);

                return ['state' => 'reserved', 'id' => (int) $row->id];
            } catch (QueryException) {
                return ['state' => 'in_flight'];
            }
        });
    }

    public function complete(int $id, int $httpStatus, string $responseJson): void
    {
        ApiIdempotencyKey::query()->whereKey($id)->update([
            'response_status' => $httpStatus,
            'response_body' => $responseJson,
        ]);
    }
}
