<?php

namespace App\Services;

use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;

class SuccessTopupClient
{
    private Client $http;
    private string $baseUrl;

    public function __construct(?Client $http = null)
    {
        $this->http = $http ?: new Client([
            'timeout' => 20,
            'connect_timeout' => 10,
            'headers' => [
                'Accept' => 'application/json',
                'Content-Type' => 'application/json',
            ],
        ]);

        $envBase = env('SUCCESSTOPUP_BASE_URL');
        $cfgBase = config('successtopup.base', 'https://api.successtopup.com');
        $this->baseUrl = rtrim($envBase ?: $cfgBase, '/');
    }

    public function recharge(
        string $key,
        string $secret,
        string $mobile,
        string $type,
        string $operatorCode,
        float $amount,
        string $trxId,
        ?string $packageId = null
    ): array {
        $payload = [
            'successtopup_key'    => $key,
            'successtopup_secret' => $secret,
            'number'              => $mobile,
            'type'                => $type,
            'operator'            => $operatorCode,
            'amount'              => $amount,
            'trxid'               => $trxId,
        ];

        if ($packageId !== null && trim($packageId) !== '') {
            $payload['package_id'] = trim($packageId);
        }

        return $this->postJson('/api/recharge', $payload);
    }

    public function status(string $key, string $secret, string $trxId): array
    {
        return $this->postJson('/api/status', [
            'successtopup_key'    => $key,
            'successtopup_secret' => $secret,
            'trxid'               => $trxId,
        ]);
    }

    public function balance(string $key, string $secret): array
    {
        // ✅ ধরে নিচ্ছি endpoint: /api/balance
        return $this->postJson('/api/balance', [
            'successtopup_key'    => $key,
            'successtopup_secret' => $secret,
        ]);
    }

    private function postJson(string $path, array $payload): array
    {
        $url = $this->baseUrl . $path;

        try {
            $res = $this->http->post($url, ['json' => $payload]);
            $raw = (string) $res->getBody();
            $json = json_decode($raw, true);

            return [
                'http_ok' => ($res->getStatusCode() >= 200 && $res->getStatusCode() < 300),
                'status'  => $res->getStatusCode(),
                'data'    => is_array($json) ? $json : null,
                'raw'     => $raw,
            ];
        } catch (GuzzleException $e) {
            return [
                'http_ok' => false,
                'status'  => 0,
                'data'    => null,
                'raw'     => null,
                'error'   => $e->getMessage(),
            ];
        }
    }

    public static function normalizeStatus(array $res, bool $allowMessageFallback = true): string
    {
        $data = is_array($res['data'] ?? null) ? $res['data'] : [];

        $rawStatus = self::firstNonEmpty([
            $data['data']['status'] ?? null,
            $data['status'] ?? null,
            $data['result']['status'] ?? null,
            $data['trx_status'] ?? null,
            $data['transaction_status'] ?? null,
            $data['state'] ?? null,
        ]);

        $normalized = self::mapStatus($rawStatus, false);
        if ($normalized !== '') {
            return $normalized;
        }

        $rawMessage = self::firstNonEmpty([
            $data['message'] ?? null,
            $data['msg'] ?? null,
            $data['data']['message'] ?? null,
            $data['data']['msg'] ?? null,
            $data['error'] ?? null,
            $res['error'] ?? null,
        ]);

        if ($allowMessageFallback) {
            $messageStatus = self::mapStatus($rawMessage, true);
            if ($messageStatus !== '') {
                return $messageStatus;
            }
        }

        $rawResult = self::firstNonEmpty([
            $data['data']['result'] ?? null,
            $data['result'] ?? null,
            $data['success'] ?? null,
            $data['ok'] ?? null,
            $data['data']['success'] ?? null,
            $data['data']['ok'] ?? null,
        ]);

        return self::mapStatus($rawResult, false);
    }

    private static function firstNonEmpty(array $values): mixed
    {
        foreach ($values as $value) {
            if ($value === null) {
                continue;
            }
            if (is_string($value)) {
                if (trim($value) === '') {
                    continue;
                }
                return $value;
            }
            if (is_array($value)) {
                continue;
            }
            return $value;
        }

        return null;
    }

    private static function mapStatus(mixed $value, bool $contains = false): string
    {
        if ($value === null) {
            return '';
        }

        if (is_bool($value)) {
            return $value ? 'success' : 'failed';
        }

        if (is_int($value) || is_float($value)) {
            if ((int) $value === 1) {
                return 'success';
            }
            if ((int) $value === 0) {
                return 'failed';
            }
            return '';
        }

        if (!is_string($value) && !is_numeric($value)) {
            return '';
        }

        $text = strtolower(trim((string) $value));
        if ($text === '') {
            return '';
        }

        $success = ['success', 'succeed', 'successful', 'approved', 'complete', 'completed', 'done', 'ok', 'passed', 'delivered', 'true', 'yes'];
        $failed = ['failed', 'fail', 'rejected', 'cancel', 'cancelled', 'canceled', 'error', 'invalid', 'denied', 'expired', 'unsuccessful', 'insufficient', 'low balance', 'not enough', 'false', 'no'];
        $pending = ['pending', 'processing', 'in_progress', 'in-progress', 'progress', 'queued', 'queue', 'waiting', 'hold', 'review', 'running', 'accepted', 'submitted', 'received', 'created', 'initiated'];

        if (!$contains) {
            if (in_array($text, $success, true)) {
                return 'success';
            }
            if (in_array($text, $failed, true)) {
                return 'failed';
            }
            if (in_array($text, $pending, true)) {
                return 'pending';
            }
            return '';
        }

        foreach ($failed as $needle) {
            if (str_contains($text, $needle)) {
                return 'failed';
            }
        }
        foreach ($success as $needle) {
            if (str_contains($text, $needle)) {
                return 'success';
            }
        }
        foreach ($pending as $needle) {
            if (str_contains($text, $needle)) {
                return 'pending';
            }
        }

        return '';
    }
}
