<?php

namespace App\Services;

use App\Models\Order;
use App\Models\OrderItem;
use App\Models\Provider;
use App\Models\ProviderLog;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Str;
use RuntimeException;
use Throwable;

class MidasbuyProviderClient
{
    public function getPlayer(Provider $provider, string $playerId, ?Order $order = null, ?OrderItem $item = null): array
    {
        return $this->post($provider, '/pubg/getPlayer', ['player_id' => $playerId], $order, $item);
    }

    public function checkCode(Provider $provider, string $ucCode, ?Order $order = null, ?OrderItem $item = null): array
    {
        return $this->post($provider, '/pubg/checkCode', ['uc_code' => $ucCode], $order, $item);
    }

    public function activate(Provider $provider, string $playerId, string $ucCode, ?Order $order = null, ?OrderItem $item = null): array
    {
        return $this->post($provider, '/pubg/activate', [
            'player_id' => $playerId,
            'uc_code' => $ucCode,
        ], $order, $item);
    }

    public function bulkActivate(Provider $provider, string $playerId, array $ucCodes, ?Order $order = null, ?OrderItem $item = null): array
    {
        return $this->post($provider, '/pubg/bulkActivate', [
            'player_id' => $playerId,
            'uc_codes' => array_values($ucCodes),
        ], $order, $item);
    }

    public function activateAsTask(Provider $provider, string $playerId, string $ucCode, ?Order $order = null, ?OrderItem $item = null): array
    {
        return $this->post($provider, '/pubg/activateAsTask', [
            'player_id' => $playerId,
            'uc_code' => $ucCode,
        ], $order, $item);
    }

    public function taskStatus(Provider $provider, string $taskId, ?Order $order = null, ?OrderItem $item = null): array
    {
        return $this->post($provider, '/pubg/taskStatus', [
            'task_id' => $taskId,
        ], $order, $item);
    }

    private function post(Provider $provider, string $endpoint, array $payload, ?Order $order, ?OrderItem $item): array
    {
        if ($provider->mode === 'mock') {
            return $this->mockResponse($endpoint, $payload, $provider, $order, $item);
        }

        $apiKey = $provider->apiKey();

        if (blank($apiKey)) {
            throw new RuntimeException('Midasbuy API key is not configured. Set MIDASBUY_API_KEY or save a provider key.');
        }

        $url = rtrim((string) $provider->base_url, '/').$endpoint;
        $started = microtime(true);
        $log = ProviderLog::create([
            'provider_id' => $provider->id,
            'order_id' => $order?->id,
            'order_item_id' => $item?->id,
            'endpoint' => $endpoint,
            'method' => 'POST',
            'request_payload' => $this->safePayload($payload),
            'status' => 'pending',
        ]);

        try {
            $response = Http::timeout($provider->timeout_seconds)
                ->withHeaders([
                    'Accept' => 'application/json',
                    $provider->auth_header ?: 'X-Api-Key' => $apiKey,
                ])
                ->post($url, $payload);
        } catch (Throwable $exception) {
            $log->update([
                'status' => 'failed',
                'latency_ms' => (int) ((microtime(true) - $started) * 1000),
                'error_message' => $exception->getMessage(),
            ]);

            throw new RuntimeException('Midasbuy request failed: '.$exception->getMessage());
        }

        $json = $response->json() ?: ['raw' => $response->body()];
        $ok = $response->successful() && ! in_array(data_get($json, 'status'), ['failed', 'error'], true);

        $log->update([
            'response_payload' => $json,
            'status_code' => $response->status(),
            'status' => $ok ? 'completed' : 'failed',
            'latency_ms' => (int) ((microtime(true) - $started) * 1000),
            'error_message' => $ok ? null : data_get($json, 'message', 'Provider rejected the request.'),
        ]);

        if (! $ok) {
            throw new RuntimeException('Midasbuy rejected the request: '.data_get($json, 'message', 'Unknown provider error.'));
        }

        return $json;
    }

    private function mockResponse(string $endpoint, array $payload, Provider $provider, ?Order $order, ?OrderItem $item): array
    {
        $response = match ($endpoint) {
            '/pubg/getPlayer' => [
                'status' => 'success',
                'player_id' => $payload['player_id'],
                'player_name' => 'Mock PUBG Player',
            ],
            '/pubg/checkCode' => [
                'status' => 'not_activated',
                'uc_code' => $payload['uc_code'],
                'amount' => 325,
            ],
            '/pubg/activate', '/pubg/activateAsTask' => [
                'status' => $endpoint === '/pubg/activateAsTask' ? 'completed' : 'success',
                'task_id' => 'MOCK-TASK-'.Str::upper(Str::random(6)),
                'player_id' => $payload['player_id'],
                'player_name' => 'Mock PUBG Player',
                'code_activated' => $payload['uc_code'],
                'activated_at' => now()->toIso8601String(),
            ],
            '/pubg/bulkActivate' => [
                'status' => 'success',
                'player_id' => $payload['player_id'],
                'results' => collect($payload['uc_codes'])->map(fn ($code) => [
                    'status' => 'success',
                    'code_activated' => $code,
                    'activated_at' => now()->toIso8601String(),
                ])->values()->all(),
            ],
            default => ['status' => 'success'],
        };

        ProviderLog::create([
            'provider_id' => $provider->id,
            'order_id' => $order?->id,
            'order_item_id' => $item?->id,
            'endpoint' => $endpoint,
            'method' => 'POST',
            'request_payload' => $this->safePayload($payload),
            'response_payload' => $response,
            'status_code' => 200,
            'status' => 'completed',
            'latency_ms' => 1,
        ]);

        return $response;
    }

    private function safePayload(array $payload): array
    {
        if (isset($payload['uc_code'])) {
            $payload['uc_code'] = $this->mask((string) $payload['uc_code']);
        }

        if (isset($payload['uc_codes'])) {
            $payload['uc_codes'] = collect($payload['uc_codes'])->map(fn ($code) => $this->mask((string) $code))->all();
        }

        return $payload;
    }

    private function mask(string $value): string
    {
        if (mb_strlen($value) <= 8) {
            return str_repeat('*', max(4, mb_strlen($value)));
        }

        return mb_substr($value, 0, 4).str_repeat('*', max(4, mb_strlen($value) - 8)).mb_substr($value, -4);
    }
}
