<?php
declare(strict_types=1);

namespace App\Services\Payment;

class TestPaymentProvider extends AbstractPaymentProvider
{
    private const SUCCESS_CARD = '4242424242424242';
    private const FAILED_CARD = '4000000000000002';

    public function createPaymentSession(array $order): array
    {
        $orderNo = (string) ($order['order_no'] ?? '');
        $amount = round((float) ($order['gross_amount'] ?? $order['amount'] ?? 0), 2);
        $currency = (string) (($order['currency'] ?? '') ?: 'TRY');
        $cardNumber = preg_replace('/\D+/', '', (string) ($order['card_number'] ?? ''));
        $scenario = strtolower((string) ($order['test_scenario'] ?? ''));
        $status = $this->resolveStatus($cardNumber, $scenario);
        $sessionId = 'test_sess_' . bin2hex(random_bytes(8));
        $reference = 'test_pay_' . bin2hex(random_bytes(8));
        $payload = [
            'provider' => 'test',
            'order_no' => $orderNo,
            'payment_session_id' => $sessionId,
            'provider_reference' => $reference,
            'amount' => number_format($amount, 2, '.', ''),
            'currency' => $currency,
            'status' => $status,
            'message' => $this->messageForStatus($status),
            'timestamp' => (string) time(),
        ];
        $payload['signature'] = $this->signature($payload);

        return [
            'ok' => true,
            'provider' => 'test',
            'provider_name' => $this->getProviderName(),
            'payment_session_id' => $sessionId,
            'provider_reference' => $reference,
            'status' => $status,
            'message' => $this->messageForStatus($status),
            'callback_payload' => $payload,
            'card_brand' => $this->cardBrand($cardNumber),
            'test_mode' => true,
        ];
    }

    public function verifyCallback(array $request): array
    {
        $payload = $this->sanitizePayload($request);
        $expected = (string) ($payload['signature'] ?? '');
        unset($payload['signature']);
        $signatureValid = $expected !== '' && hash_equals($this->signature($payload), $expected);
        $status = in_array((string) ($payload['status'] ?? ''), ['paid', 'failed', 'pending'], true)
            ? (string) $payload['status']
            : 'failed';

        return [
            'ok' => $signatureValid,
            'provider' => 'test',
            'signature_valid' => $signatureValid,
            'order_no' => (string) ($payload['order_no'] ?? ''),
            'provider_reference' => (string) ($payload['provider_reference'] ?? ''),
            'payment_session_id' => (string) ($payload['payment_session_id'] ?? ''),
            'amount' => (float) ($payload['amount'] ?? 0),
            'currency' => (string) (($payload['currency'] ?? '') ?: 'TRY'),
            'status' => $signatureValid ? $status : 'failed',
            'message' => $signatureValid ? (string) ($payload['message'] ?? $this->messageForStatus($status)) : 'Test odeme imzasi dogrulanamadi.',
            'payload' => $payload,
        ];
    }

    public function refund(array $order): array
    {
        return [
            'ok' => false,
            'provider' => 'test',
            'message' => 'Test refund akisi sonraki finans bolumunde detaylandirilacak.',
            'todo' => true,
        ];
    }

    public function getProviderName(): string
    {
        return 'TestPaymentProvider';
    }

    public function supportsSavedCard(): bool
    {
        return false;
    }

    public function supportsTokenization(): bool
    {
        return false;
    }

    private function resolveStatus(string $cardNumber, string $scenario): string
    {
        if ($scenario === 'pending') {
            return 'pending';
        }

        if ($cardNumber === self::FAILED_CARD || $scenario === 'failed') {
            return 'failed';
        }

        return 'paid';
    }

    private function messageForStatus(string $status): string
    {
        return match ($status) {
            'paid' => 'Test odeme basarili.',
            'pending' => 'Test odeme beklemede.',
            default => 'Test odeme basarisiz.',
        };
    }

    private function signature(array $payload): string
    {
        ksort($payload);
        $secret = (string) (($this->config['test_secret'] ?? '') ?: 'zalorox_test_payment_secret');

        return hash_hmac('sha256', json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), $secret);
    }

    private function cardBrand(string $cardNumber): string
    {
        if (str_starts_with($cardNumber, '4')) {
            return 'visa';
        }

        if (preg_match('/^(5[1-5]|2[2-7])/', $cardNumber)) {
            return 'mastercard';
        }

        if (str_starts_with($cardNumber, '9792')) {
            return 'troy';
        }

        return 'card';
    }
}
