<?php

declare(strict_types=1);

/*
 * This file is part of Exchanger.
 *
 * (c) Florian Voutzinos <florian@voutzinos.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace Exchanger\Service;

use Exchanger\Contract\ExchangeRate;
use Exchanger\Contract\ExchangeRateQuery;
use Exchanger\Contract\ExchangeRateService;
use Exchanger\Exception\ChainException;

/**
 * A service using other services in a chain.
 *
 * @author Florian Voutzinos <florian@voutzinos.com>
 */
final class Chain implements ExchangeRateService
{
    /**
     * The services.
     *
     * @var array|ExchangeRateService[]
     */
    private $services;

    /**
     * Creates a new chain service.
     *
     * @param ExchangeRateService[] $services
     */
    public function __construct(iterable $services = [])
    {
        if (!is_array($services)) {
            /** @var \Iterator $services */
            $services = iterator_to_array($services);
        }

        $this->services = $services;
    }

    /**
     * {@inheritdoc}
     */
    public function getExchangeRate(ExchangeRateQuery $exchangeQuery): ExchangeRate
    {
        $exceptions = [];

        foreach ($this->services as $service) {
            if (!$service->supportQuery($exchangeQuery)) {
                continue;
            }

            try {
                return $service->getExchangeRate($exchangeQuery);
            } catch (\Throwable $e) {
                $exceptions[] = $e;
            }
        }

        throw new ChainException($exceptions);
    }

    /**
     * {@inheritdoc}
     */
    public function supportQuery(ExchangeRateQuery $exchangeQuery): bool
    {
        foreach ($this->services as $service) {
            if ($service->supportQuery($exchangeQuery)) {
                return true;
            }
        }

        return false;
    }

    /**
     * {@inheritdoc}
     */
    public function getName(): string
    {
        return 'chain';
    }
}
