<?php

namespace App\Services\Payment;

use App\Services\BaseService;
use GuzzleHttp\Client;

class JdPayService extends BaseService
{
    public const CHANNEL = 'JDpay';

    public const PAY_STATUS_SUCCESS = '3';
    public const PAY_STATUS_FAIL = '4';

    public const REMIT_STATUS_SUCCESS = '2';
    public const REMIT_STATUS_FAIL = '3';

    public static function getMerchantId()
    {
        return config('app.jd_pay_mch_id');
    }

    public static function getSecret()
    {
        return config('app.jd_pay_key');
    }

    public static function getNotifyUrl(): string
    {
        return rtrim(config('app.url'), '/') . '/api/pay/harvest';
    }

    public static function getRemitNotifyUrl(): string
    {
        return rtrim(config('app.url'), '/') . '/api/pay/notify';
    }

    public static function getClient(): Client
    {
        return new Client([
            'timeout' => 10.0,
        ]);
    }

    public static function isChannel(?string $channel): bool
    {
        return strtolower((string)$channel) === strtolower(self::CHANNEL)
            || strtolower((string)$channel) === 'jdpay'
            || (string)$channel === 'JD钱包';
    }

    public static function canUserRecharge($userId): bool
    {
        $allowedUserIds = array_values(array_filter(array_map(
            'trim',
            explode(',', (string)config('app.jd_pay_recharge_user_ids', ''))
        )));

        if (empty($allowedUserIds)) {
            return true;
        }

        return in_array((string)$userId, $allowedUserIds, true);
    }

    public static function amount($amount): string
    {
        return number_format((float)$amount, 2, '.', '');
    }

    public static function signature(array $values): string
    {
        $values[] = self::getSecret();
        return strtoupper(md5(implode('&', $values)));
    }

    public static function pay($amount, string $orderNo): array
    {
        $amount = self::amount($amount);
        $data = [
            'userCode' => self::getMerchantId(),
            'orderCode' => $orderNo,
            'amount' => $amount,
            'callbackUrl' => self::getNotifyUrl(),
        ];
        $data['sign'] = self::signature([$orderNo, $amount, $data['userCode']]);

        return self::post(config('app.jd_pay_gateway'), $data);
    }

    public static function queryPayOrder(string $orderNo = '', string $customerOrderNo = ''): array
    {
        $data = [
            'userCode' => self::getMerchantId(),
            'orderCode' => $orderNo,
            'customerOrderCode' => $customerOrderNo,
        ];
        $data['sign'] = self::signature([$data['orderCode'], $data['customerOrderCode'], $data['userCode']]);

        return self::post(config('app.jd_pay_query_gateway'), $data);
    }

    public static function remit($amount, string $orderNo, string $address): array
    {
        $amount = self::amount($amount);
        $data = [
            'userCode' => self::getMerchantId(),
            'orderCode' => $orderNo,
            'amount' => $amount,
            'address' => $address,
            'callbackUrl' => self::getRemitNotifyUrl(),
        ];
        $data['sign'] = self::signature([$orderNo, $amount, $address, $data['userCode']]);

        return self::post(config('app.jd_remit_gateway'), $data);
    }

    public static function queryRemitOrder(string $orderNo = '', string $customerOrderNo = ''): array
    {
        $data = [
            'userCode' => self::getMerchantId(),
            'orderCode' => $orderNo,
            'customerOrderCode' => $customerOrderNo,
        ];
        $data['sign'] = self::signature([$data['orderCode'], $data['customerOrderCode'], $data['userCode']]);

        return self::post(config('app.jd_remit_query_gateway'), $data);
    }

    public static function balance(): array
    {
        $timestamp = (string)round(microtime(true) * 1000);
        $userCode = self::getMerchantId();
        $sign = self::signature([$userCode, $timestamp]);

        $response = self::getClient()->get(rtrim(config('app.jd_balance_gateway'), '/') . '/' . $userCode, [
            'query' => [
                'timestamp' => $timestamp,
                'sign' => $sign,
            ],
        ]);

        return json_decode($response->getBody()->getContents(), true) ?: [];
    }

    public static function verifyPayNotify(array $params): bool
    {
        if (($params['userCode'] ?? '') !== self::getMerchantId()) {
            return false;
        }

        $sign = self::signature([
            $params['orderCode'] ?? '',
            (string)($params['amount'] ?? ''),
            $params['userCode'] ?? '',
            (string)($params['status'] ?? ''),
        ]);

        return hash_equals($sign, strtoupper((string)($params['sign'] ?? '')));
    }

    public static function verifyRemitNotify(array $params): bool
    {
        if (($params['userCode'] ?? '') !== self::getMerchantId()) {
            return false;
        }

        $sign = self::signature([
            $params['orderCode'] ?? '',
            $params['customerOrderCode'] ?? '',
            (string)($params['amount'] ?? ''),
            $params['userCode'] ?? '',
            (string)($params['status'] ?? ''),
        ]);

        return hash_equals($sign, strtoupper((string)($params['sign'] ?? '')));
    }

    private static function post(string $url, array $data): array
    {
        $response = self::getClient()->post($url, [
            'form_params' => $data,
            'headers' => [
                'Content-Type' => 'application/x-www-form-urlencoded',
            ],
        ]);

        return json_decode($response->getBody()->getContents(), true) ?: [];
    }

    public static function getWhere(array $search = []): array
    {
        return [];
    }
}
