<?php

namespace App\Http\Controllers;

use App\Services\Paddle\Exceptions\PaddleException;
use App\Services\Paddle\PaddleTransactionService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;

class PaddleReturnController extends Controller
{
    public function __construct(private readonly PaddleTransactionService $transactions) {}

    /**
     * Handle the incoming request.
     */
    public function __invoke(Request $request): RedirectResponse
    {
        $transactionId = $this->resolveTransactionId($request);
        $fallback = $this->resolveFallbackUrl();

        if (! $transactionId) {
            return redirect()->to($fallback);
        }

        try {
            $transaction = $this->transactions->retrieve($transactionId);
        } catch (PaddleException $exception) {
            Log::warning('Paddle return failed to load transaction', [
                'transaction_id' => $transactionId,
                'error' => $exception->getMessage(),
                'status' => $exception->status(),
            ]);

            return redirect()->to($fallback);
        }

        $customData = $this->extractCustomData($transaction);
        $status = Str::lower((string) ($transaction['status'] ?? ''));
        $successUrl = $customData['success_url'] ?? null;
        $cancelUrl = $customData['cancel_url'] ?? $customData['return_url'] ?? null;

        $target = $this->isSuccessStatus($status) ? $successUrl : $cancelUrl;
        $target = $this->resolveSafeRedirect($target, $fallback);

        return redirect()->to($target);
    }

    protected function resolveTransactionId(Request $request): ?string
    {
        $candidate = $request->query('_ptxn')
            ?? $request->query('ptxn')
            ?? $request->query('transaction_id');

        if (! is_string($candidate) || $candidate === '') {
            return null;
        }

        return $candidate;
    }

    protected function resolveFallbackUrl(): string
    {
        return rtrim((string) config('app.url', url('/')), '/') ?: url('/');
    }

    /**
     * @param  array<string, mixed>  $transaction
     * @return array<string, mixed>
     */
    protected function extractCustomData(array $transaction): array
    {
        $customData = Arr::get($transaction, 'custom_data', []);

        if (! is_array($customData)) {
            $customData = [];
        }

        $legacy = Arr::get($transaction, 'customData');
        if (is_array($legacy)) {
            $customData = array_merge($customData, $legacy);
        }

        $metadata = Arr::get($transaction, 'metadata');
        if (is_array($metadata)) {
            $customData = array_merge($customData, $metadata);
        }

        return $customData;
    }

    protected function isSuccessStatus(string $status): bool
    {
        return in_array($status, ['completed', 'paid'], true);
    }

    protected function resolveSafeRedirect(?string $target, string $fallback): string
    {
        if (! $target) {
            return $fallback;
        }

        if (Str::startsWith($target, ['/'])) {
            return $target;
        }

        $appHost = parse_url($fallback, PHP_URL_HOST);
        $targetHost = parse_url($target, PHP_URL_HOST);

        if ($appHost && $targetHost && Str::lower($appHost) === Str::lower($targetHost)) {
            return $target;
        }

        return $fallback;
    }
}
