<?php

namespace App\Services\Credentials;

use App\Models\Client;
use App\Models\PlatformConnection;
use App\Models\SecureCredential;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Crypt;

class CredentialVault
{
    public function payload(?SecureCredential $credential): array
    {
        if (! $credential || blank($credential->encrypted_payload)) {
            return [];
        }

        try {
            $decoded = Crypt::decryptString($credential->encrypted_payload);
            $payload = json_decode($decoded, true);

            return is_array($payload) ? $payload : [];
        } catch (\Throwable) {
            return [];
        }
    }

    public function maskedPayload(?SecureCredential $credential): array
    {
        return collect($this->payload($credential))
            ->map(fn ($value, $key) => $this->mask((string) $value, (string) $key))
            ->all();
    }

    public function upsertForConnection(PlatformConnection $connection, array $incoming, array $sensitiveKeys, array $nonSensitiveKeys = []): ?SecureCredential
    {
        $credential = $connection->secureCredential;
        $current = $this->payload($credential);
        $payload = $current;

        foreach ($sensitiveKeys as $key) {
            if (array_key_exists($key, $incoming) && filled($incoming[$key])) {
                $payload[$key] = trim((string) $incoming[$key]);
            }
        }

        foreach ($nonSensitiveKeys as $key) {
            if (array_key_exists($key, $incoming) && filled($incoming[$key])) {
                $payload[$key] = trim((string) $incoming[$key]);
            }
        }

        if (empty($payload)) {
            return $credential;
        }

        $credentialData = [
            'client_id' => $connection->client_id,
            'platform' => $connection->platform,
            'credential_type' => $this->credentialType($connection->platform),
            'name' => $connection->connection_name.' Token Kasası',
            'encrypted_payload' => Crypt::encryptString(json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)),
            'is_active' => true,
            'last_error' => null,
        ];

        if ($credential) {
            $credential->update($credentialData);
        } else {
            $credential = SecureCredential::create($credentialData);
            $connection->forceFill(['secure_credential_id' => $credential->id])->save();
        }

        return $credential->refresh();
    }

    public function saveOAuthTokens(PlatformConnection $connection, array $tokens): SecureCredential
    {
        $credential = $connection->secureCredential;
        $current = $this->payload($credential);
        $payload = array_filter(array_merge($current, [
            'access_token' => $tokens['access_token'] ?? null,
            'refresh_token' => $tokens['refresh_token'] ?? ($current['refresh_token'] ?? null),
            'token_type' => $tokens['token_type'] ?? null,
            'scope' => $tokens['scope'] ?? null,
            'oauth_created_at' => now()->toIso8601String(),
        ]), fn ($value) => $value !== null && $value !== '');

        $expiresAt = null;
        if (! empty($tokens['expires_in'])) {
            $expiresAt = now()->addSeconds((int) $tokens['expires_in']);
        }

        $credentialData = [
            'client_id' => $connection->client_id,
            'platform' => $connection->platform,
            'credential_type' => $this->credentialType($connection->platform),
            'name' => $connection->connection_name.' OAuth Tokenları',
            'encrypted_payload' => Crypt::encryptString(json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)),
            'expires_at' => $expiresAt,
            'is_active' => true,
            'last_error' => null,
            'last_checked_at' => now(),
        ];

        if ($credential) {
            $credential->update($credentialData);
        } else {
            $credential = SecureCredential::create($credentialData);
            $connection->forceFill(['secure_credential_id' => $credential->id])->save();
        }

        return $credential->refresh();
    }

    public function markChecked(?SecureCredential $credential, ?string $error = null): void
    {
        if (! $credential) {
            return;
        }

        $credential->update([
            'last_checked_at' => now(),
            'last_error' => $error,
            'is_active' => $error === null,
        ]);
    }

    public function mask(string $value, string $key = ''): string
    {
        if ($value === '') {
            return '';
        }

        if (str_contains($key, 'client_id') || str_contains($key, 'customer_id') || str_contains($key, 'account_id') || str_contains($key, 'property_id')) {
            return strlen($value) <= 6 ? str_repeat('*', strlen($value)) : substr($value, 0, 3).'•••'.substr($value, -3);
        }

        if (strlen($value) <= 8) {
            return str_repeat('•', strlen($value));
        }

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

    private function credentialType(string $platform): string
    {
        return match ($platform) {
            'google_ads' => 'google_oauth_ads',
            'search_console' => 'google_oauth_search_console',
            'ga4' => 'google_oauth_analytics',
            'meta_ads' => 'meta_marketing_api',
            default => 'api_credentials',
        };
    }
}
