<?php

namespace App\Services\Sync;

use App\Models\Ga4TrafficSnapshot;
use App\Models\PlatformConnection;
use App\Services\Credentials\CredentialVault;
use App\Services\Integrations\GoogleOAuthService;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;

class Ga4SyncService
{
    public function __construct(
        private readonly CredentialVault $vault,
        private readonly GoogleOAuthService $oauth,
    ) {}

    public function sync(PlatformConnection $connection, string $from, string $to): SyncResult
    {
        $started = microtime(true);

        try {
            $payload = $this->vault->payload($connection->secureCredential);
            $propertyId = $payload['property_id'] ?? $connection->account_id;
            if (blank($propertyId)) {
                return SyncResult::failed('GA4 property_id eksik.');
            }

            $rows = $this->runReport($connection, (string) $propertyId, $from, $to);
            $count = 0;

            foreach ($rows as $row) {
                $dimensions = $row['dimensionValues'] ?? [];
                $metrics = $row['metricValues'] ?? [];
                $date = $this->gaDate(Arr::get($dimensions, '0.value'));
                $channel = Arr::get($dimensions, '1.value', '(not set)');
                if (blank($date)) {
                    continue;
                }

                Ga4TrafficSnapshot::updateOrCreate(
                    [
                        'platform_connection_id' => $connection->id,
                        'date' => $date,
                        'dimension_type' => 'sessionDefaultChannelGroup',
                        'dimension_value' => $channel,
                    ],
                    [
                        'client_id' => $connection->client_id,
                        'sessions' => (int) Arr::get($metrics, '0.value', 0),
                        'total_users' => (int) Arr::get($metrics, '1.value', 0),
                        'screen_page_views' => (int) Arr::get($metrics, '2.value', 0),
                        'conversions' => (float) Arr::get($metrics, '3.value', 0),
                        'total_revenue' => (float) Arr::get($metrics, '4.value', 0),
                        'event_count' => (int) Arr::get($metrics, '5.value', 0),
                        'raw_json' => json_encode($row, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
                    ]
                );
                $count++;
            }

            $duration = (int) round((microtime(true) - $started) * 1000);

            return SyncResult::success('GA4 verileri senkronize edildi.', ['traffic_rows' => $count], $duration);
        } catch (\Throwable $e) {
            $duration = (int) round((microtime(true) - $started) * 1000);

            return SyncResult::failed('GA4 senkronizasyonu başarısız.', $e->getMessage(), [], $duration);
        }
    }

    private function runReport(PlatformConnection $connection, string $propertyId, string $from, string $to): array
    {
        $endpoint = "https://analyticsdata.googleapis.com/v1beta/properties/{$propertyId}:runReport";
        $response = Http::withToken($this->oauth->accessTokenFromRefreshToken($connection))->timeout(90)->post($endpoint, [
            'dateRanges' => [['startDate' => $from, 'endDate' => $to]],
            'dimensions' => [
                ['name' => 'date'],
                ['name' => 'sessionDefaultChannelGroup'],
            ],
            'metrics' => [
                ['name' => 'sessions'],
                ['name' => 'totalUsers'],
                ['name' => 'screenPageViews'],
                ['name' => 'conversions'],
                ['name' => 'totalRevenue'],
                ['name' => 'eventCount'],
            ],
            'limit' => 250000,
        ]);

        if (! $response->successful()) {
            throw new \RuntimeException('GA4 runReport başarısız: '.Str::limit($response->body(), 1000));
        }

        return $response->json('rows') ?? [];
    }

    private function gaDate(?string $value): ?string
    {
        if (! $value || strlen($value) !== 8) {
            return $value;
        }

        return substr($value, 0, 4).'-'.substr($value, 4, 2).'-'.substr($value, 6, 2);
    }
}
