<?php

namespace App\Services\Payments;

use App\Models\Booking;
use App\Models\Payment;
use App\Models\PaymentGateway;
use App\Models\WebhookEvent;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;

class StripeGateway implements PaymentGatewayInterface
{
    public function createPaymentIntent(Booking $booking): Payment
    {
        // TODO: replace with real Stripe SDK call to create PaymentIntent and return client_secret
        // Example:
        // $stripe = new \Stripe\StripeClient($booking->gateway->credentials['secret']);
        // $intent = $stripe->paymentIntents->create([...]);
        $clientSecret = 'pi_' . Str::random(12) . '_secret_' . Str::random(16);
        $payment = Payment::create([
            'booking_id' => $booking->id,
            'payment_gateway_id' => $booking->payment_gateway_id,
            'amount' => $booking->amount,
            'currency' => $booking->currency,
            'transaction_id' => Str::uuid()->toString(),
            'status' => 'initiated',
            'payload' => [
                'provider' => 'stripe',
                'client_secret' => $clientSecret,
            ],
        ]);

        return $payment;
    }

    public function handleWebhook(Request $request, PaymentGateway $gateway): ?Payment
    {
        $payload = $request->getContent();
        $signature = $request->header('Stripe-Signature');
        $secret = $gateway->webhook_secret;

        if (! $this->verifySignature($payload, $signature, $secret)) {
            throw new AccessDeniedHttpException('Invalid signature');
        }

        $decoded = json_decode($payload, true);

        $transactionId = data_get($decoded, 'data.object.id');
        $status = data_get($decoded, 'type') === 'charge.succeeded' ? 'captured' : 'failed';

        $payment = Payment::where('transaction_id', $transactionId)->first();
        if ($payment) {
            $payment->update([
                'status' => $status === 'captured' ? 'captured' : 'failed',
                'payload' => $decoded,
                'captured_at' => $status === 'captured' ? now() : null,
            ]);
        }

        return $payment;
    }

    public function capture(Payment $payment): Payment
    {
        $payment->update([
            'status' => 'captured',
            'captured_at' => now(),
        ]);

        return $payment;
    }

    public function refund(Payment $payment, float $amount): Payment
    {
        $payment->update([
            'status' => $amount < $payment->amount ? 'partial_refund' : 'refunded',
            'refunded_at' => now(),
            'payload' => array_merge($payment->payload ?? [], ['refunded_amount' => $amount]),
        ]);

        return $payment;
    }

    public function payout(Payment $payment): bool
    {
        return true;
    }

    private function verifySignature(string $payload, ?string $header, ?string $secret): bool
    {
        if (! $secret || ! $header) {
            return false;
        }

        // Expect header like: t=timestamp,v1=signature
        $parts = collect(explode(',', $header))->mapWithKeys(function ($item) {
            [$k, $v] = array_pad(explode('=', $item, 2), 2, null);
            return [$k => $v];
        });

        $timestamp = $parts->get('t');
        $sig = $parts->get('v1');

        if (! $timestamp || ! $sig) {
            return false;
        }

        $signedPayload = $timestamp.'.'.$payload;
        $expected = hash_hmac('sha256', $signedPayload, $secret);

        return hash_equals($expected, $sig);
    }
}
