<?php

namespace App\Serp\Providers;

use App\Serp\Contracts\AsyncSerpProvider;
use App\Serp\Data\SerpQuery;
use App\Serp\Data\SerpResponse;
use App\Serp\Data\SerpResultData;
use App\Serp\Data\SerpSubmission;
use App\Serp\Data\SerpTaskResult;
use App\Serp\Exceptions\PermanentProviderException;
use App\Serp\Exceptions\ProviderConfigurationException;
use App\Serp\Exceptions\ProviderRateLimitException;
use App\Serp\Exceptions\ProviderTimeoutException;

final class FakeSerpProvider implements AsyncSerpProvider
{
    public static string $mode = 'success';

    public static array $results = [];

    public function key(): string
    {
        return 'fake';
    }

    public function supports(SerpQuery $q): bool
    {
        return in_array($q->searchEngine, ['google', 'bing'], true);
    }

    public function search(SerpQuery $q): SerpResponse
    {
        $this->guard();
        $this->errors();
        $results = self::$results ?: [new SerpResultData(1, 'https://example.com/result', 'Example', 'example.com', 'Deterministic test result')];

        return new SerpResponse($this->key(), $results, 'fake-reference', $q->limit);
    }

    public function submit(SerpQuery $q): SerpSubmission
    {
        $this->guard();
        $this->errors();

        return new SerpSubmission($this->key(), '00000000-0000-0000-0000-000000000001', 0.0, 'USD', 20100);
    }

    public function collect(string $taskId, int $limit): SerpTaskResult
    {
        $this->guard();
        $this->errors();
        if (self::$mode === 'waiting') {
            return SerpTaskResult::waiting(40601);
        }$response = $this->search(new SerpQuery('fake', 'google', 'TR', 'tr', 'desktop', $limit));
        $response = new SerpResponse($this->key(), $response->results, $taskId, $limit);

        return SerpTaskResult::ready($response, 0.0, 'USD', 20000);
    }

    private function guard(): void
    {
        if (! (app()->environment('testing') || (app()->environment('local') && config('serp.allow_fake_local')))) {
            throw new ProviderConfigurationException('Fake provider forbidden.');
        }
    }

    private function errors(): void
    {
        if (self::$mode === 'timeout') {
            throw new ProviderTimeoutException('secret timeout');
        }if (self::$mode === 'rate_limit') {
            throw new ProviderRateLimitException('secret rate');
        }if (self::$mode === 'permanent') {
            throw new PermanentProviderException('secret permanent');
        }
    }
}
