<?php

namespace App\Serp\Operations;

use App\Models\SerpOperationState;
use App\Serp\Data\ProviderHealth;
use App\Serp\Exceptions\UnexpectedProviderResponseException;
use App\Serp\Providers\DataForSeo\DataForSeoClient;
use App\Serp\Providers\DataForSeo\DataForSeoErrorClassifier;
use Illuminate\Support\Facades\Cache;

final class DataForSeoHealthService
{
    public function __construct(private DataForSeoClient $client, private DataForSeoErrorClassifier $errors, private KillSwitch $kill, private OperationAuditLogger $audit) {}

    public function validateConfig(): array
    {
        $configured = (string) config('serp.dataforseo.login') !== '' && (string) config('serp.dataforseo.password') !== '';
        $base = rtrim((string) config('serp.dataforseo.base_url'), '/');
        $parts = parse_url($base);
        if (! is_array($parts) || ($parts['scheme'] ?? null) !== 'https' || strtolower($parts['host'] ?? '') !== 'api.dataforseo.com') {
            throw new \InvalidArgumentException('Invalid provider endpoint.');
        }if ($configured) {
            $this->client->validateConfiguration();
        }
        foreach (['daily_budget_usd', 'monthly_budget_usd', 'low_balance_usd', 'critical_balance_usd'] as $key) {
            if (Money::micros((string) config('serp.'.$key)) <= 0) {
                throw new \InvalidArgumentException('Invalid '.$key);
            }
        }

        return ['provider' => 'dataforseo', 'host' => 'api.dataforseo.com', 'tls' => true, 'credentials_configured' => $configured, 'operation_mode' => app(ActivationManager::class)->state()->value];
    }

    public function remote(bool $fresh = false): ProviderHealth
    {
        return Cache::remember('serp:dataforseo:health', $fresh ? 0 : (int) config('serp.health_ttl_seconds'), function () {
            $data = $this->client->userData();
            $status = $data['status_code'] ?? null;
            if (! is_int($status)) {
                throw new UnexpectedProviderResponseException('Health status missing.');
            }if ($status !== 20000) {
                throw $this->errors->api($status);
            }$task = $data['tasks'][0] ?? null;
            if (! is_array($task) || ($task['status_code'] ?? null) !== 20000) {
                throw new UnexpectedProviderResponseException('Health task malformed.');
            }$balance = $task['result'][0]['money']['balance'] ?? null;
            if (! is_int($balance) && ! is_float($balance) && ! is_string($balance)) {
                throw new UnexpectedProviderResponseException('Balance missing.');
            }$health = new ProviderHealth('dataforseo', Money::micros($balance), 20000, now('UTC'));
            SerpOperationState::query()->updateOrCreate(['id' => 1], ['last_health_at' => $health->checkedAt, 'last_balance_micros' => $health->balanceMicros, 'last_provider_status_code' => 20000, 'last_provider_success_at' => $health->checkedAt, 'last_error_category' => null]);
            if ($health->balanceMicros < Money::micros((string) config('serp.critical_balance_usd'))) {
                $this->kill->activate('critical_low_balance');
            } elseif ($health->balanceMicros < Money::micros((string) config('serp.low_balance_usd'))) {
                $this->audit->record('low_balance', ['cost_micros' => $health->balanceMicros]);
            }

            return $health;
        });
    }
}
