<?php

declare(strict_types=1);

namespace Kreait\Firebase\ServiceAccount;

use Google\Auth\CredentialsLoader;
use Kreait\Firebase\Exception\ServiceAccountDiscoveryFailed;
use Kreait\Firebase\ServiceAccount;
use Throwable;

class Discoverer
{
    /**
     * @var callable[]
     */
    private $methods;

    /**
     * @param callable[] $methods
     */
    public function __construct(array $methods = null)
    {
        $this->methods = $methods ?? $this->getDefaultMethods();
    }

    public function getDefaultMethods(): array
    {
        return [
            new Discovery\FromEnvironmentVariable('FIREBASE_CREDENTIALS'),
            new Discovery\FromEnvironmentVariable(CredentialsLoader::ENV_VAR),
            new Discovery\FromGoogleWellKnownFile(),
            new Discovery\OnGoogleCloudPlatform(),
        ];
    }

    public function discover(): ServiceAccount
    {
        $messages = [];

        $serviceAccount = \array_reduce($this->methods, static function ($discovered, callable $method) use (&$messages) {
            try {
                $discovered = $discovered ?? $method();
            } catch (Throwable $e) {
                $messages[] = $e->getMessage();
            }

            return $discovered;
        });

        if (!($serviceAccount instanceof ServiceAccount)) {
            throw new ServiceAccountDiscoveryFailed(\implode(\PHP_EOL, $messages));
        }

        return $serviceAccount;
    }
}
